Fossil

Check-in [161a210687]
Login

Check-in [161a210687]

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

Overview
Comment:Merge in trunk
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | wiki-history
Files: files | file ages | folders
SHA3-256: 161a210687e98cd0cb18a3aa9ebbd7064dbeca02db8e8426e55a77cc763664d0
User & Date: george 2020-04-26 23:10:00.156
Context
2020-05-26
18:27
Merge in trunk (version-2.11) ... (check-in: 6819e2ffab user: george tags: wiki-history)
2020-04-26
23:10
Merge in trunk ... (check-in: 161a210687 user: george tags: wiki-history)
20:41
Fix overlength lines and commenting irregularities in http_ssl.c. No code changes. ... (check-in: 483ac3db83 user: drh tags: trunk)
2019-12-01
20:18
Special UI controls added onto the /whistory webpage for easy comparison of arbitrary versions of a wiki page. ... (check-in: ec04c8b4a8 user: george tags: wiki-history)
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.classic.
97
98
99
100
101
102
103


104
105
LIB += $(LIB.$(HOST_OS))

TCC.DragonFly += -DUSE_PREAD
TCC.FreeBSD += -DUSE_PREAD
TCC.NetBSD += -DUSE_PREAD
TCC.OpenBSD += -DUSE_PREAD
TCC += $(TCC.$(HOST_OS))



include $(SRCDIR)/main.mk







>
>


97
98
99
100
101
102
103
104
105
106
107
LIB += $(LIB.$(HOST_OS))

TCC.DragonFly += -DUSE_PREAD
TCC.FreeBSD += -DUSE_PREAD
TCC.NetBSD += -DUSE_PREAD
TCC.OpenBSD += -DUSE_PREAD
TCC += $(TCC.$(HOST_OS))

APPNAME = fossil$(E)

include $(SRCDIR)/main.mk
Changes to auto.def.
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
    define FOSSIL_DYNAMIC_BUILD
}

# Check for libraries that need to be sorted out early
cc-check-function-in-lib iconv iconv

# Helper for OpenSSL checking
proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto}}} {
    msg-checking "Checking for $msg..."
    set rc 0
    if {[is_mingw]} {
        lappend libs -lgdi32 -lwsock32 -lcrypt32
    }
    if {[info exists ::zlib_lib]} {
        lappend libs $::zlib_lib







|







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
    define FOSSIL_DYNAMIC_BUILD
}

# Check for libraries that need to be sorted out early
cc-check-function-in-lib iconv iconv

# Helper for OpenSSL checking
proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto -lpthread}}} {
    msg-checking "Checking for $msg..."
    set rc 0
    if {[is_mingw]} {
        lappend libs -lgdi32 -lwsock32 -lcrypt32
    }
    if {[info exists ::zlib_lib]} {
        lappend libs $::zlib_lib
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
        set ssldir [file dirname $autosetup(dir)]/compat/openssl
        if {![file isdirectory $ssldir]} {
            user-error "The OpenSSL in source tree directory does not exist"
        }
        set msg "ssl in $ssldir"
        set cflags "-I$ssldir/include"
        set ldflags "-L$ssldir"
        set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a"
        set found [check-for-openssl "ssl in source tree" "$cflags $ldflags" $ssllibs]
    } else {
        if {$ssldirs in {auto ""}} {
            catch {
                set cflags [exec pkg-config openssl --cflags-only-I]
                set ldflags [exec pkg-config openssl --libs-only-L]
                set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]







|







349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
        set ssldir [file dirname $autosetup(dir)]/compat/openssl
        if {![file isdirectory $ssldir]} {
            user-error "The OpenSSL in source tree directory does not exist"
        }
        set msg "ssl in $ssldir"
        set cflags "-I$ssldir/include"
        set ldflags "-L$ssldir"
        set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a -lpthread"
        set found [check-for-openssl "ssl in source tree" "$cflags $ldflags" $ssllibs]
    } else {
        if {$ssldirs in {auto ""}} {
            catch {
                set cflags [exec pkg-config openssl --cflags-only-I]
                set ldflags [exec pkg-config openssl --libs-only-L]
                set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
Changes to skins/README.md.
1
2
3
4
5
6





7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29


30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
Built-in Skins
==============

Each subdirectory under this folder describes a built-in "skin".
There are four files in each subdirectory for the CSS, the "details"
file, the footer, and the header for that skin.






To improve an existing built-in skin, simply edit the appropriate
files and recompile.

To add a new skin:

   1.   Create a new subdirectory under skins/.  (The new directory is
        called "skins/newskin" below but you should use a new original
        name, of course.)

   2.   Add files skins/newskin/css.txt, skins/newskin/details.txt,
        skins/newskin/footer.txt and skins/newskin/header.txt.
        Be sure to "fossil add" these files.

   3.   Go to the src/ directory and rerun "tclsh makemake.tcl".  This
        step rebuilds the various makefiles so that they have dependencies
        on the skin files you just installed.

   4.   Edit the BuiltinSkin[] array near the top of the src/skins.c source
        file so that it describes and references the "newskin" skin.

   5.   Type "make" to rebuild.



Development Hints
-----------------

One way to develop a new skin is to copy the baseline files (css.txt,
details.txt, footer.txt, and header.txt) into a working directory $WORKDIR
then launch Fossil with a command-line option "--skin $WORKDIR".  Example:


        cp -r skins/default newskin
        fossil ui --skin ./newskin

When the argument to --skin contains one or more '/' characters, the
appropriate skin files are read from disk from the directory specified.
So after launching fossil as shown above, you can edit the newskin/css.txt,
newskin/details.txt, newskin/footer.txt, and newskin/header.txt files using
your favorite text editor, then press Reload on your browser to see
immediate results.




|
|
>
>
>
>
>











|
|










>
>




|
|
>






|
<
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
Built-in Skins
==============

Each subdirectory under this folder describes a built-in "skin".
There are five key files in each subdirectory:

  * `css.txt`	&rarr; The CSS for the skin
  * `details.txt` &rarr; Skin-specific settings
  * `footer.txt` &rarr; Text of the Content Footer for each page
  * `header.txt` &rarr; Text of the Content Header for each page
  * `js.txt` &rarr; Javascript included in the Content Footer

To improve an existing built-in skin, simply edit the appropriate
files and recompile.

To add a new skin:

   1.   Create a new subdirectory under skins/.  (The new directory is
        called "skins/newskin" below but you should use a new original
        name, of course.)

   2.   Add files skins/newskin/css.txt, skins/newskin/details.txt,
        skins/newskin/footer.txt, skins/newskin/header.txt, and
        skins/newskin/js.txt. Be sure to "fossil add" these files.

   3.   Go to the src/ directory and rerun "tclsh makemake.tcl".  This
        step rebuilds the various makefiles so that they have dependencies
        on the skin files you just installed.

   4.   Edit the BuiltinSkin[] array near the top of the src/skins.c source
        file so that it describes and references the "newskin" skin.

   5.   Type "make" to rebuild.

See the [custom skin documentation](../www/customskin.md) for more information.

Development Hints
-----------------

One way to develop a new skin is to copy the baseline files (css.txt,
details.txt, footer.txt, header.txt, and js.txt) into a working 
directory $WORKDIR then launch Fossil with a command-line option 
"--skin $WORKDIR".  Example:

        cp -r skins/default newskin
        fossil ui --skin ./newskin

When the argument to --skin contains one or more '/' characters, the
appropriate skin files are read from disk from the directory specified.
So after launching fossil as shown above, you can edit the newskin/*.txt

files using your favorite text editor, then press Reload on your browser
to see immediate results.
Changes to skins/ardoise/css.txt.
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  max-width: 1200px;
  margin: 0 auto;
  box-sizing: border-box
}
.column,
.columns {
  width: 100%;
  float: left;
  box-sizing: border-box
}
@media (min-width:400px) {
  .container {
    width: 95%;
    padding: 0
  }







|







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  max-width: 1200px;
  margin: 0 auto;
  box-sizing: border-box
}
.column,
.columns {
  width: 100%;
  /*float: left; can break README.md in /dir view*/
  box-sizing: border-box
}
@media (min-width:400px) {
  .container {
    width: 95%;
    padding: 0
  }
800
801
802
803
804
805
806






807
808
809
810
811
812
813
ul.browser li.file:hover,
ul.browser li.file:hover * {
  background-color: #333
}
td.browser,
td.tktDescLabel {
  vertical-align: top






}
div.filetreeline {
  display: table;
  width: 100%;
  white-space: nowrap
}
.filetree {







>
>
>
>
>
>







800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
ul.browser li.file:hover,
ul.browser li.file:hover * {
  background-color: #333
}
td.browser,
td.tktDescLabel {
  vertical-align: top
}
td.tktTlOpen {
  color: #ffa0a0;
}
td.tktTlClosed {
  color: #555;
}
div.filetreeline {
  display: table;
  width: 100%;
  white-space: nowrap
}
.filetree {
Changes to skins/default/css.txt.
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    overflow: auto;
    border: 1px solid #ccc;
    border-radius: 5px;
}
.content blockquote {
    padding: 0 15px;
}
div.forumHierRoot blockquote, div.forumHier blockquote, div.forumEdit blockquote {
    background-color: rgba(65, 131, 196, 0.1);
    border-left: 3px solid #254769;
    padding: .1em 1em;
}

table.report {
    cursor: auto;







|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    overflow: auto;
    border: 1px solid #ccc;
    border-radius: 5px;
}
.content blockquote {
    padding: 0 15px;
}
div.forumHierRoot blockquote, div.forumHier blockquote, div.forumEdit blockquote, div.forumTime blockquote, div.forumTimeline blockquote {
    background-color: rgba(65, 131, 196, 0.1);
    border-left: 3px solid #254769;
    padding: .1em 1em;
}

table.report {
    cursor: auto;
Changes to skins/default/header.txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div class="header">
  <div class="title"><h1>$<project_name></h1>$<title></div>
    <div class="status"><th1>
 if {[info exists login]} {
   html "$login — <a href='$home/login'>Logout</a>\n"
 } else {
   html "<a href='$home/login'>Login</a>\n"
 }
    </th1></div>
</div>
<div class="mainmenu">
<th1>
proc menulink {url name cls} {
  upvar current_page current
  upvar home home
  if {[string range $url 0 [string length $current]] eq "/$current"} {
    html "<a href='$home$url' class='active $cls'>$name</a>\n"
  } else {
    html "<a href='$home$url' class='$cls'>$name</a>\n"
  }
}
html "<a id='hbbtn' href='/sitemap'>&#9776;</a>"
menulink $index_page Home {}
if {[anycap jor]} {
  menulink /timeline Timeline {}
}
if {[hascap oh]} {
  menulink /dir?ci=tip Files desktoponly
}




|
















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div class="header">
  <div class="title"><h1>$<project_name></h1>$<title></div>
    <div class="status"><th1>
 if {[info exists login]} {
   html "<a href='$home/login'>$login</a>\n"
 } else {
   html "<a href='$home/login'>Login</a>\n"
 }
    </th1></div>
</div>
<div class="mainmenu">
<th1>
proc menulink {url name cls} {
  upvar current_page current
  upvar home home
  if {[string range $url 0 [string length $current]] eq "/$current"} {
    html "<a href='$home$url' class='active $cls'>$name</a>\n"
  } else {
    html "<a href='$home$url' class='$cls'>$name</a>\n"
  }
}
html "<a id='hbbtn' href='$home/sitemap'>&#9776;</a>"
menulink $index_page Home {}
if {[anycap jor]} {
  menulink /timeline Timeline {}
}
if {[hascap oh]} {
  menulink /dir?ci=tip Files desktoponly
}
Changes to skins/eagle/css.txt.
286
287
288
289
290
291
292








293
294
295
296
297
298
299

/* format for values on ticket display page */
td.tktDspValue {
  text-align: left;
  vertical-align: top;
  background-color: #485D7B;
}









/* format for example table cells on the report edit page */
td.rpteditex {
  border-width: thin;
  border-color: white;
  border-style: solid;
}







>
>
>
>
>
>
>
>







286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

/* format for values on ticket display page */
td.tktDspValue {
  text-align: left;
  vertical-align: top;
  background-color: #485D7B;
}

/* Ticket display on timelines */
td.tktTlOpen {
  color: #ffc0c0;
}
td.tktTlClose {
  color: #c0c0c0;
}

/* format for example table cells on the report edit page */
td.rpteditex {
  border-width: thin;
  border-color: white;
  border-style: solid;
}
Changes to skins/xekri/css.txt.
693
694
695
696
697
698
699





700
701
702
703
704
705
706

/* format for values on ticket display page */
td.tktDspValue {
  background-color: #111;
  text-align: left;
  vertical-align: top;
}






/* format for ticket error messages */
span.tktError {
  color: #f00;
  font-weight: bold;
}








>
>
>
>
>







693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711

/* format for values on ticket display page */
td.tktDspValue {
  background-color: #111;
  text-align: left;
  vertical-align: top;
}

/* Tickets on timelines */
td.tktTlOpen {
  color: #ffa0a0;
}

/* format for ticket error messages */
span.tktError {
  color: #f00;
  font-weight: bold;
}

Added src/accordion.js.






































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* Attach appropriate javascript to each ".accordion" button so that
** it expands and contracts when clicked.
** The uncompressed source code for the SVG icons can be found on the
** wiki page "branch/accordion-experiments" in the Fossil repository.
*/
var acc_svgdata = ["data:image/svg+xml,"+
  "%3Csvg xmlns='http:"+"/"+"/www.w3.org/2000/svg' viewBox='0 0 16 16'%3E"+
  "%3Cpath style='fill:black;opacity:0' d='M16,16H0V0h16v16z'/%3E"+
  "%3Cpath style='fill:rgb(240,240,240)' d='M14,14H2V2h12v12z'/%3E"+
  "%3Cpath style='fill:rgb(64,64,64)' d='M13,13H3V3h10v10z'/%3E"+
  "%3Cpath style='fill:rgb(248,248,248)' d='M12,12H4V4h8v8z'/%3E"+
  "%3Cpath style='fill:rgb(80,128,208)' d='", "'/%3E%3C/svg%3E",
  "M5,7h2v-2h2v2h2v2h-2v2h-2v-2h-2z", "M11,9H5V7h6v6z"];
var a = document.getElementsByClassName("accordion");
for(var i=0; i<a.length; i++){
  var img = document.createElement("img");
  img.src = acc_svgdata[0]+acc_svgdata[2]+acc_svgdata[1];
  img.className = "accordion_btn accordion_btn_plus";
  a[i].insertBefore(img,a[i].firstChild);
  img = document.createElement("img");
  img.src = acc_svgdata[0]+acc_svgdata[3]+acc_svgdata[1];
  img.className = "accordion_btn accordion_btn_minus";
  a[i].insertBefore(img,a[i].firstChild);
  var p = a[i].nextElementSibling;
  p.style.maxHeight = p.scrollHeight + "px";
  a[i].addEventListener("click",function(){
    var x = this.nextElementSibling;
    if( this.classList.contains("accordion_closed") ){
      x.style.maxHeight = x.scrollHeight + "px";
    }else{
      x.style.maxHeight = "0";
    }
    this.classList.toggle("accordion_closed");
  });
}
Changes to src/add.c.
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
      int nOrig;
      file_tree_name(g.argv[i], &orig, 0, 1);
      zOrig = blob_str(&orig);
      nOrig = blob_size(&orig);
      db_prepare(&q,
         "SELECT pathname FROM vfile"
         " WHERE vid=%d"
         "   AND (pathname='%q' %s OR (pathname>'%q/' %s AND pathname<'%q0' %s))"
         " ORDER BY 1",
         vid, zOrig, filename_collation(), zOrig, filename_collation(),
         zOrig, filename_collation()
      );
      while( db_step(&q)==SQLITE_ROW ){
        const char *zPath = db_column_text(&q, 0);
        int nPath = db_column_bytes(&q, 0);







|







934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
      int nOrig;
      file_tree_name(g.argv[i], &orig, 0, 1);
      zOrig = blob_str(&orig);
      nOrig = blob_size(&orig);
      db_prepare(&q,
         "SELECT pathname FROM vfile"
         " WHERE vid=%d"
         "  AND (pathname='%q' %s OR (pathname>'%q/' %s AND pathname<'%q0' %s))"
         " ORDER BY 1",
         vid, zOrig, filename_collation(), zOrig, filename_collation(),
         zOrig, filename_collation()
      );
      while( db_step(&q)==SQLITE_ROW ){
        const char *zPath = db_column_text(&q, 0);
        int nPath = db_column_bytes(&q, 0);
966
967
968
969
970
971
972

973
974
975
976
977
978
979
980
981
982
983
  while( db_step(&q)==SQLITE_ROW ){
    const char *zFrom = db_column_text(&q, 0);
    const char *zTo = db_column_text(&q, 1);
    mv_one_file(vid, zFrom, zTo, dryRunFlag);
    if( moveFiles ) add_file_to_move(zFrom, zTo);
  }
  db_finalize(&q);

  db_end_transaction(0);
  if( moveFiles ) process_files_to_move(dryRunFlag);
}

/*
** Function for stash_apply to be able to restore a file and indicate
** newly ADDED state.
*/
int stash_add_files_in_sfile(int vid){
  return add_files_in_sfile(vid);
}







>











966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
  while( db_step(&q)==SQLITE_ROW ){
    const char *zFrom = db_column_text(&q, 0);
    const char *zTo = db_column_text(&q, 1);
    mv_one_file(vid, zFrom, zTo, dryRunFlag);
    if( moveFiles ) add_file_to_move(zFrom, zTo);
  }
  db_finalize(&q);
  undo_reset();
  db_end_transaction(0);
  if( moveFiles ) process_files_to_move(dryRunFlag);
}

/*
** Function for stash_apply to be able to restore a file and indicate
** newly ADDED state.
*/
int stash_add_files_in_sfile(int vid){
  return add_files_in_sfile(vid);
}
Changes to src/alerts.c.
44
45
46
47
48
49
50

51
52
53
54
55
56
57
@ -- In the last case the suname column points from the subscriber entry
@ -- to the USER entry.
@ --
@ -- The ssub field is a string where each character indicates a particular
@ -- type of event to subscribe to.  Choices:
@ --     a - Announcements
@ --     c - Check-ins

@ --     t - Ticket changes
@ --     w - Wiki changes
@ -- Probably different codes will be added in the future.  In the future
@ -- we might also add a separate table that allows subscribing to email
@ -- notifications for specific branches or tags or tickets.
@ --
@ CREATE TABLE repository.subscriber(







>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
@ -- In the last case the suname column points from the subscriber entry
@ -- to the USER entry.
@ --
@ -- The ssub field is a string where each character indicates a particular
@ -- type of event to subscribe to.  Choices:
@ --     a - Announcements
@ --     c - Check-ins
@ --     f - Forum posts
@ --     t - Ticket changes
@ --     w - Wiki changes
@ -- Probably different codes will be added in the future.  In the future
@ -- we might also add a separate table that allows subscribing to email
@ -- notifications for specific branches or tags or tickets.
@ --
@ CREATE TABLE repository.subscriber(
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
void alert_schema(int bOnlyIfEnabled){
  if( !alert_tables_exist() ){
    if( bOnlyIfEnabled
     && fossil_strcmp(db_get("email-send-method",0),"off")==0
    ){
      return;  /* Don't create table for disabled email */
    }
    db_multi_exec(zAlertInit/*works-like:""*/);
    alert_triggers_enable();
  }else if( !db_table_has_column("repository","pending_alert","sentMod") ){
    db_multi_exec(
      "ALTER TABLE repository.pending_alert"
      " ADD COLUMN sentMod BOOLEAN DEFAULT false;"
    );
  }







|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
void alert_schema(int bOnlyIfEnabled){
  if( !alert_tables_exist() ){
    if( bOnlyIfEnabled
     && fossil_strcmp(db_get("email-send-method",0),"off")==0
    ){
      return;  /* Don't create table for disabled email */
    }
    db_exec_sql(zAlertInit);
    alert_triggers_enable();
  }else if( !db_table_has_column("repository","pending_alert","sentMod") ){
    db_multi_exec(
      "ALTER TABLE repository.pending_alert"
      " ADD COLUMN sentMod BOOLEAN DEFAULT false;"
    );
  }
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
** Insert a "Subscriber List" submenu link if the current user
** is an administrator.
*/
void alert_submenu_common(void){
  if( g.perm.Admin ){
    if( fossil_strcmp(g.zPath,"subscribers") ){
      style_submenu_element("List Subscribers","%R/subscribers");
    }
    if( fossil_strcmp(g.zPath,"subscribe") ){
      style_submenu_element("Add New Subscriber","%R/subscribe");
    }
  }
}








|







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/*
** Insert a "Subscriber List" submenu link if the current user
** is an administrator.
*/
void alert_submenu_common(void){
  if( g.perm.Admin ){
    if( fossil_strcmp(g.zPath,"subscribers") ){
      style_submenu_element("Subscribers","%R/subscribers");
    }
    if( fossil_strcmp(g.zPath,"subscribe") ){
      style_submenu_element("Add New Subscriber","%R/subscribe");
    }
  }
}

236
237
238
239
240
241
242







243
244
245
246
247
248
249
                   "eurl", "", 0);
  @ <p><b>Required.</b>
  @ This is URL used as the basename for hyperlinks included in
  @ email alert text.  Omit the trailing "/".
  @ Suggested value: "%h(g.zBaseURL)"
  @ (Property: "email-url")</p>
  @ <hr>








  entry_attribute("\"Return-Path\" email address", 20, "email-self",
                   "eself", "", 0);
  @ <p><b>Required.</b>
  @ This is the email to which email notification bounces should be sent.
  @ In cases where the email notification does not align with a specific
  @ Fossil login account (for example, digest messages), this is also







>
>
>
>
>
>
>







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
                   "eurl", "", 0);
  @ <p><b>Required.</b>
  @ This is URL used as the basename for hyperlinks included in
  @ email alert text.  Omit the trailing "/".
  @ Suggested value: "%h(g.zBaseURL)"
  @ (Property: "email-url")</p>
  @ <hr>

  entry_attribute("Administrator email address", 40, "email-admin",
                   "eadmin", "", 0);
  @ <p>This is the email for the human administrator for the system.
  @ Abuse and trouble reports and password reset requests are send here.
  @ (Property: "email-admin")</p>
  @ <hr>

  entry_attribute("\"Return-Path\" email address", 20, "email-self",
                   "eself", "", 0);
  @ <p><b>Required.</b>
  @ This is the email to which email notification bounces should be sent.
  @ In cases where the email notification does not align with a specific
  @ Fossil login account (for example, digest messages), this is also
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
  @ transmitted via the SMTP protocol (rfc5321) to a "Mail Submission
  @ Agent" or "MSA" (rfc4409) at the hostname shown here.  Optionally
  @ append a colon and TCP port number (ex: smtp.example.com:587).
  @ The default TCP port number is 25.
  @ (Property: "email-send-relayhost")</p>
  @ <hr>

  entry_attribute("Administrator email address", 40, "email-admin",
                   "eadmin", "", 0);
  @ <p>This is the email for the human administrator for the system.
  @ Abuse and trouble reports are send here.
  @ (Property: "email-admin")</p>
  @ <hr>

  @ <p><input type="submit"  name="submit" value="Apply Changes" /></p>
  @ </div></form>
  db_end_transaction(0);
  style_footer();
}

#if 0







<
<
<
<
<
<
<







303
304
305
306
307
308
309







310
311
312
313
314
315
316
  @ transmitted via the SMTP protocol (rfc5321) to a "Mail Submission
  @ Agent" or "MSA" (rfc4409) at the hostname shown here.  Optionally
  @ append a colon and TCP port number (ex: smtp.example.com:587).
  @ The default TCP port number is 25.
  @ (Property: "email-send-relayhost")</p>
  @ <hr>








  @ <p><input type="submit"  name="submit" value="Apply Changes" /></p>
  @ </div></form>
  db_end_transaction(0);
  style_footer();
}

#if 0
572
573
574
575
576
577
578

579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
      return 1;
    }
  }
  return 0;
}

/*

** Make a copy of the input string up to but not including the
** first cTerm character.
**
** Verify that the string really that is to be copied really is a
** valid email address.  If it is not, then return NULL.
**
** This routine is more restrictive than necessary.  It does not
** allow comments, IP address, quoted strings, or certain uncommon
** characters.  The only non-alphanumerics allowed in the local
** part are "_", "+", "-" and "+".
*/
char *email_copy_addr(const char *z, char cTerm ){
  int i;
  int nAt = 0;
  int nDot = 0;
  char c;
  if( z[0]=='.' ) return 0;  /* Local part cannot begin with "." */
  for(i=0; (c = z[i])!=0 && c!=cTerm; i++){
    if( fossil_isalnum(c) ){







>
|
|

<
|
<
<
|
<
<

|







573
574
575
576
577
578
579
580
581
582
583

584


585


586
587
588
589
590
591
592
593
594
      return 1;
    }
  }
  return 0;
}

/*
** Determine whether or not the input string is a valid email address.
** Only look at character up to but not including the first \000 or
** the first cTerm character, whichever comes first.
**

** Return the length of the email addresss string in bytes if the email


** address is valid.  If the email address is misformed, return 0.


*/
int email_address_is_valid(const char *z, char cTerm){
  int i;
  int nAt = 0;
  int nDot = 0;
  char c;
  if( z[0]=='.' ) return 0;  /* Local part cannot begin with "." */
  for(i=0; (c = z[i])!=0 && c!=cTerm; i++){
    if( fossil_isalnum(c) ){
617
618
619
620
621
622
623

624
625














626
627
628
629
630
631
632
633
    }else{
      return 0;   /* Anything else is an error */
    }
  }
  if( c!=cTerm ) return 0;    /* Missing terminator */
  if( nAt==0 ) return 0;      /* No "@" found anywhere */
  if( nDot==0 ) return 0;     /* No "." in the domain */


  /* If we reach this point, the email address is valid */














  return mprintf("%.*s", i, z);
}

/*
** Scan the input string for a valid email address enclosed in <...>
** If the string contains one or more email addresses, extract the first
** one into memory obtained from mprintf() and return a pointer to it.
** If no valid email address can be found, return NULL.







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







614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
    }else{
      return 0;   /* Anything else is an error */
    }
  }
  if( c!=cTerm ) return 0;    /* Missing terminator */
  if( nAt==0 ) return 0;      /* No "@" found anywhere */
  if( nDot==0 ) return 0;     /* No "." in the domain */
  return i;
}

/*
** Make a copy of the input string up to but not including the
** first cTerm character.
**
** Verify that the string really that is to be copied really is a
** valid email address.  If it is not, then return NULL.
**
** This routine is more restrictive than necessary.  It does not
** allow comments, IP address, quoted strings, or certain uncommon
** characters.  The only non-alphanumerics allowed in the local
** part are "_", "+", "-" and "+".
*/
char *email_copy_addr(const char *z, char cTerm ){
  int i = email_address_is_valid(z, cTerm);
  return i==0 ? 0 : mprintf("%.*s", i, z);
}

/*
** Scan the input string for a valid email address enclosed in <...>
** If the string contains one or more email addresses, extract the first
** one into memory obtained from mprintf() and return a pointer to it.
** If no valid email address can be found, return NULL.
657
658
659
660
661
662
663




























664
665
666
667
668
669
670
){
  const char *zIn = (const char*)sqlite3_value_text(argv[0]);
  char *zOut = alert_find_emailaddr(zIn);
  if( zOut ){
    sqlite3_result_text(context, zOut, -1, fossil_free);
  }
}





























/*
** Return the hostname portion of an email address - the part following
** the @
*/
char *alert_hostname(const char *zAddr){
  char *z = strchr(zAddr, '@');







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







669
670
671
672
673
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
704
705
706
707
708
709
710
){
  const char *zIn = (const char*)sqlite3_value_text(argv[0]);
  char *zOut = alert_find_emailaddr(zIn);
  if( zOut ){
    sqlite3_result_text(context, zOut, -1, fossil_free);
  }
}

/*
** SQL function:  display_name(X)
**
** If X is a string, search for a user name at the beginning of that
** string.  The user name must be followed by an email address.  If
** found, return the user name.  If not found, return NULL.
**
** This routine is used to extract the display name from the USER.INFO
** field.
*/
void alert_display_name_func(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zIn = (const char*)sqlite3_value_text(argv[0]);
  int i;
  if( zIn==0 ) return;
  while( fossil_isspace(zIn[0]) ) zIn++;
  for(i=0; zIn[i] && zIn[i]!='<' && zIn[i]!='\n'; i++){}
  if( zIn[i]=='<' ){
    while( i>0 && fossil_isspace(zIn[i-1]) ){ i--; }
    if( i>0 ){
      sqlite3_result_text(context, zIn, i, SQLITE_TRANSIENT);
    }
  }
}

/*
** Return the hostname portion of an email address - the part following
** the @
*/
char *alert_hostname(const char *zAddr){
  char *z = strchr(zAddr, '@');
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798

799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
**
**     From:
**     Date:
**     Message-Id:
**     Content-Type:
**     Content-Transfer-Encoding:
**     MIME-Version:
**     X-Fossil-From:
**     
** The caller maintains ownership of the input Blobs.  This routine will
** read the Blobs and send them onward to the email system, but it will
** not free them.
**
** The Message-Id: field is added if there is not already a Message-Id
** in the pHdr parameter.
**
** If the zFromName argument is not NULL, then it should be a human-readable
** name or handle for the sender.  In that case, "From:" becomes a made-up
** email address based on a hash of zFromName and the domain of email-self,
** and an additional "X-Fossil-From:" field is inserted with the email-self
** address.  Downstream software might use the X-Fossil-From header to set
** the envelope-from address of the email.  If zFromName is a NULL pointer, 
** then the "From:" is set to the email-self value and X-Fossil-From is
** omitted.
*/
void alert_send(
  AlertSender *p,           /* Emailer context */
  Blob *pHdr,               /* Email header (incomplete) */
  Blob *pBody,              /* Email body */
  const char *zFromName     /* Optional human-readable name of sender */
){
  Blob all, *pOut;
  u64 r1, r2;
  if( p->mFlags & ALERT_TRACE ){
    fossil_print("Sending email\n");
  }
  if( fossil_strcmp(p->zDest, "off")==0 ){
    return;
  }

  if( fossil_strcmp(p->zDest, "blob")==0 ){
    pOut = &p->out;
    if( blob_size(pOut) ){
      blob_appendf(pOut, "%.72c\n", '=');
    }
  }else{
    blob_init(&all, 0, 0);
    pOut = &all;
  }
  blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr));
  if( p->zFrom==0 || p->zFrom[0]==0 ){
    return;  /* email-self is not set.  Error will be reported separately */
  }else if( zFromName ){
    blob_appendf(pOut, "From: %s <%s@%s>\r\n",
       zFromName, alert_mailbox_name(zFromName), alert_hostname(p->zFrom));
    blob_appendf(pOut, "X-Fossil-From: <%s>\r\n", p->zFrom);
  }else{
    blob_appendf(pOut, "From: <%s>\r\n", p->zFrom);
  }
  blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0)));
  if( strstr(blob_str(pHdr), "\r\nMessage-Id:")==0 ){
    /* Message-id format:  "<$(date)x$(random)@$(from-host)>" where $(date) is
    ** the current unix-time in hex, $(random) is a 64-bit random number,







|











|
|

|
















>






<








|







800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845

846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
**
**     From:
**     Date:
**     Message-Id:
**     Content-Type:
**     Content-Transfer-Encoding:
**     MIME-Version:
**     Sender:
**     
** The caller maintains ownership of the input Blobs.  This routine will
** read the Blobs and send them onward to the email system, but it will
** not free them.
**
** The Message-Id: field is added if there is not already a Message-Id
** in the pHdr parameter.
**
** If the zFromName argument is not NULL, then it should be a human-readable
** name or handle for the sender.  In that case, "From:" becomes a made-up
** email address based on a hash of zFromName and the domain of email-self,
** and an additional "Sender:" field is inserted with the email-self
** address.  Downstream software might use the Sender header to set
** the envelope-from address of the email.  If zFromName is a NULL pointer, 
** then the "From:" is set to the email-self value and Sender is
** omitted.
*/
void alert_send(
  AlertSender *p,           /* Emailer context */
  Blob *pHdr,               /* Email header (incomplete) */
  Blob *pBody,              /* Email body */
  const char *zFromName     /* Optional human-readable name of sender */
){
  Blob all, *pOut;
  u64 r1, r2;
  if( p->mFlags & ALERT_TRACE ){
    fossil_print("Sending email\n");
  }
  if( fossil_strcmp(p->zDest, "off")==0 ){
    return;
  }
  blob_init(&all, 0, 0);
  if( fossil_strcmp(p->zDest, "blob")==0 ){
    pOut = &p->out;
    if( blob_size(pOut) ){
      blob_appendf(pOut, "%.72c\n", '=');
    }
  }else{

    pOut = &all;
  }
  blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr));
  if( p->zFrom==0 || p->zFrom[0]==0 ){
    return;  /* email-self is not set.  Error will be reported separately */
  }else if( zFromName ){
    blob_appendf(pOut, "From: %s <%s@%s>\r\n",
       zFromName, alert_mailbox_name(zFromName), alert_hostname(p->zFrom));
    blob_appendf(pOut, "Sender: <%s>\r\n", p->zFrom);
  }else{
    blob_appendf(pOut, "From: <%s>\r\n", p->zFrom);
  }
  blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0)));
  if( strstr(blob_str(pHdr), "\r\nMessage-Id:")==0 ){
    /* Message-id format:  "<$(date)x$(random)@$(from-host)>" where $(date) is
    ** the current unix-time in hex, $(random) is a 64-bit random number,
877
878
879
880
881
882
883
















884
885
886
887
888
889
890
    email_header_to_free(nTo, azTo);
    blob_add_final_newline(&all);
    fossil_print("%s", blob_str(&all));
  }
  blob_reset(&all);
}

















/*
** SETTING: email-send-method         width=5 default=off
** Determine the method used to send email.  Allowed values are
** "off", "relay", "pipe", "dir", "db", and "stdout".  The "off" value
** means no email is ever sent.  The "relay" value means emails are sent
** to an Mail Sending Agent using SMTP located at email-send-relayhost.
** The "pipe" value means email messages are piped into a command 







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







917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
    email_header_to_free(nTo, azTo);
    blob_add_final_newline(&all);
    fossil_print("%s", blob_str(&all));
  }
  blob_reset(&all);
}

/*
** SETTING: email-url                 width=40
** This URL is used as the basename for hyperlinks included in email alert
** text. Omit the trailing "/".
*/
/*
** SETTING: email-admin               width=40
** This is the email address for the human administrator for the system. 
** Abuse and trouble reports and password reset requests are send here.
*/
/*
** SETTING: email-subname             width=16
** This is a short name used to identifies the repository in the Subject:
** line of email alerts. Traditionally this name is included in square
** brackets. Examples: "[fossil-src]", "[sqlite-src]".
*/
/*
** SETTING: email-send-method         width=5 default=off
** Determine the method used to send email.  Allowed values are
** "off", "relay", "pipe", "dir", "db", and "stdout".  The "off" value
** means no email is ever sent.  The "relay" value means emails are sent
** to an Mail Sending Agent using SMTP located at email-send-relayhost.
** The "pipe" value means email messages are piped into a command 
1150
1151
1152
1153
1154
1155
1156









1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168




1169
1170
1171
1172
1173
1174
1175
){
  const char *zEAddr;
  int i, j, n;
  char c;

  *peErr = 0;
  *pzErr = 0;










  /* Check the validity of the email address.
  **
  **  (1) Exactly one '@' character.
  **  (2) No other characters besides [a-zA-Z0-9._+-]
  **
  **  The local part is currently more restrictive than RFC 5322 allows:
  **  https://stackoverflow.com/a/2049510/142454  We will expand this as
  **  necessary.
  */
  zEAddr = P("e");
  if( zEAddr==0 ) return 0;




  for(i=j=n=0; (c = zEAddr[i])!=0; i++){
    if( c=='@' ){
      n = i;
      j++;
      continue;
    }
    if( !fossil_isalnum(c) && c!='.' && c!='_' && c!='-' && c!='+' ){







>
>
>
>
>
>
>
>
>











|
>
>
>
>







1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
){
  const char *zEAddr;
  int i, j, n;
  char c;

  *peErr = 0;
  *pzErr = 0;

  /* Verify the captcha first */
  if( needCaptcha ){
    if( !captcha_is_correct(1) ){
      *peErr = 2;
      *pzErr = mprintf("incorrect security code");
      return 0;
    }
  }

  /* Check the validity of the email address.
  **
  **  (1) Exactly one '@' character.
  **  (2) No other characters besides [a-zA-Z0-9._+-]
  **
  **  The local part is currently more restrictive than RFC 5322 allows:
  **  https://stackoverflow.com/a/2049510/142454  We will expand this as
  **  necessary.
  */
  zEAddr = P("e");
  if( zEAddr==0 ){
    *peErr = 1;
    *pzErr = mprintf("required");
    return 0;
  }
  for(i=j=n=0; (c = zEAddr[i])!=0; i++){
    if( c=='@' ){
      n = i;
      j++;
      continue;
    }
    if( !fossil_isalnum(c) && c!='.' && c!='_' && c!='-' && c!='+' ){
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
  }
  if( n>i-5 ){
    *peErr = 1;
    *pzErr = mprintf("email domain too short");
     return 0;
  }

  /* Verify the captcha */
  if( needCaptcha && !captcha_is_correct(1) ){
    *peErr = 2;
    *pzErr = mprintf("incorrect security code");
    return 0;
  }

  /* Check to make sure the email address is available for reuse */
  if( db_exists("SELECT 1 FROM subscriber WHERE semail=%Q", zEAddr) ){
    *peErr = 1;
    *pzErr = mprintf("this email address is used by someone else");







|
<
|
|







1260
1261
1262
1263
1264
1265
1266
1267

1268
1269
1270
1271
1272
1273
1274
1275
1276
  }
  if( n>i-5 ){
    *peErr = 1;
    *pzErr = mprintf("email domain too short");
     return 0;
  }

  if( authorized_subscription_email(zEAddr)==0 ){

    *peErr = 1;
    *pzErr = mprintf("not an authorized email address");
    return 0;
  }

  /* Check to make sure the email address is available for reuse */
  if( db_exists("SELECT 1 FROM subscriber WHERE semail=%Q", zEAddr) ){
    *peErr = 1;
    *pzErr = mprintf("this email address is used by someone else");
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
**
** The Alerts permission ("7") is required to access this
** page.  To allow anonymous passers-by to sign up for email
** notification, set Email-Alerts on user "nobody" or "anonymous".
*/
void subscribe_page(void){
  int needCaptcha;
  unsigned int uSeed;
  const char *zDecoded;
  char *zCaptcha = 0;
  char *zErr = 0;
  int eErr = 0;
  int di;

  if( alert_webpages_disabled() ) return;







|







1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
**
** The Alerts permission ("7") is required to access this
** page.  To allow anonymous passers-by to sign up for email
** notification, set Email-Alerts on user "nobody" or "anonymous".
*/
void subscribe_page(void){
  int needCaptcha;
  unsigned int uSeed = 0;
  const char *zDecoded;
  char *zCaptcha = 0;
  char *zErr = 0;
  int eErr = 0;
  int di;

  if( alert_webpages_disabled() ) return;
1289
1290
1291
1292
1293
1294
1295




1296
1297
1298
1299
1300
1301
1302
      style_submenu_element("My Subscription","%R/alerts");
    }else{
      /* Everybody else jumps to the page to administer their own
      ** account only. */
      cgi_redirectf("%R/alerts");
      return;
    }




  }
  alert_submenu_common();
  needCaptcha = !login_is_individual();
  if( P("submit")
   && cgi_csrf_safe(1)
   && subscribe_error_check(&eErr,&zErr,needCaptcha)
  ){







>
>
>
>







1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
      style_submenu_element("My Subscription","%R/alerts");
    }else{
      /* Everybody else jumps to the page to administer their own
      ** account only. */
      cgi_redirectf("%R/alerts");
      return;
    }
  }
  if( !g.perm.Admin && !db_get_boolean("anon-subscribe",1) ){
    register_page();
    return;
  }
  alert_submenu_common();
  needCaptcha = !login_is_individual();
  if( P("submit")
   && cgi_csrf_safe(1)
   && subscribe_error_check(&eErr,&zErr,needCaptcha)
  ){
1310
1311
1312
1313
1314
1315
1316

1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336

1337



1338
1339
1340
1341
1342
1343
1344
    if( suname==0 && needCaptcha==0 && !g.perm.Admin ) suname = g.zLogin;
    if( suname && suname[0]==0 ) suname = 0;
    if( PB("sa") ) ssub[nsub++] = 'a';
    if( g.perm.Read && PB("sc") )    ssub[nsub++] = 'c';
    if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f';
    if( g.perm.RdTkt && PB("st") )   ssub[nsub++] = 't';
    if( g.perm.RdWiki && PB("sw") )  ssub[nsub++] = 'w';

    ssub[nsub] = 0;
    db_multi_exec(
      "INSERT INTO subscriber(semail,suname,"
      "  sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)"
      "VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)",
      /* semail */    zEAddr,
      /* suname */    suname,
      /* sverified */ needCaptcha==0,
      /* sdigest */   PB("di"),
      /* ssub */      ssub,
      /* smip */      g.zIpAddr
    );
    id = db_last_insert_rowid();
    zCode = db_text(0,
         "SELECT hex(subscriberCode) FROM subscriber WHERE subscriberId=%lld",
         id);
    if( !needCaptcha ){
      /* The new subscription has been added on behalf of a logged-in user.
      ** No verification is required.  Jump immediately to /alerts page.
      */

      cgi_redirectf("%R/alerts/%s", zCode);



      return;
    }else{
      /* We need to send a verification email */
      Blob hdr, body;
      AlertSender *pSender = alert_sender_new(0,0);
      blob_init(&hdr,0,0);
      blob_init(&body,0,0);







>




















>
|
>
>
>







1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
    if( suname==0 && needCaptcha==0 && !g.perm.Admin ) suname = g.zLogin;
    if( suname && suname[0]==0 ) suname = 0;
    if( PB("sa") ) ssub[nsub++] = 'a';
    if( g.perm.Read && PB("sc") )    ssub[nsub++] = 'c';
    if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f';
    if( g.perm.RdTkt && PB("st") )   ssub[nsub++] = 't';
    if( g.perm.RdWiki && PB("sw") )  ssub[nsub++] = 'w';
    if( g.perm.RdForum && PB("sx") ) ssub[nsub++] = 'x';
    ssub[nsub] = 0;
    db_multi_exec(
      "INSERT INTO subscriber(semail,suname,"
      "  sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)"
      "VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)",
      /* semail */    zEAddr,
      /* suname */    suname,
      /* sverified */ needCaptcha==0,
      /* sdigest */   PB("di"),
      /* ssub */      ssub,
      /* smip */      g.zIpAddr
    );
    id = db_last_insert_rowid();
    zCode = db_text(0,
         "SELECT hex(subscriberCode) FROM subscriber WHERE subscriberId=%lld",
         id);
    if( !needCaptcha ){
      /* The new subscription has been added on behalf of a logged-in user.
      ** No verification is required.  Jump immediately to /alerts page.
      */
      if( g.perm.Admin ){
        cgi_redirectf("%R/alerts/%.32s", zCode);
      }else{
        cgi_redirectf("%R/alerts");
      }
      return;
    }else{
      /* We need to send a verification email */
      Blob hdr, body;
      AlertSender *pSender = alert_sender_new(0,0);
      blob_init(&hdr,0,0);
      blob_init(&body,0,0);
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
        @ <p>The following internal error was encountered while trying
        @ to send the confirmation email:
        @ <blockquote><pre>
        @ %h(pSender->zErr)
        @ </pre></blockquote>
      }else{
        @ <p>An email has been sent to "%h(zEAddr)". That email contains a
        @ hyperlink that you must click on in order to activate your
        @ subscription.</p>
      }
      alert_sender_free(pSender);
      style_footer();
    }
    return;
  }







|







1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
        @ <p>The following internal error was encountered while trying
        @ to send the confirmation email:
        @ <blockquote><pre>
        @ %h(pSender->zErr)
        @ </pre></blockquote>
      }else{
        @ <p>An email has been sent to "%h(zEAddr)". That email contains a
        @ hyperlink that you must click to activate your
        @ subscription.</p>
      }
      alert_sender_free(pSender);
      style_footer();
    }
    return;
  }
1384
1385
1386
1387
1388
1389
1390





1391

1392
1393
1394
1395
1396

1397
1398
1399
1400
1401
1402
1403
  @  <td><input type="text" name="e" value="%h(PD("e",""))" size="30"></td>
  @ <tr>
  if( eErr==1 ){
    @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
  }
  @ </tr>
  if( needCaptcha ){





    uSeed = captcha_seed();

    zDecoded = captcha_decode(uSeed);
    zCaptcha = captcha_render(zDecoded);
    @ <tr>
    @  <td class="form_label">Security Code:</td>
    @  <td><input type="text" name="captcha" value="" size="30">

    @  <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
    @ </tr>
    if( eErr==2 ){
      @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
    }
    @ </tr>
  }







>
>
>
>
>
|
>




|
>







1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
  @  <td><input type="text" name="e" value="%h(PD("e",""))" size="30"></td>
  @ <tr>
  if( eErr==1 ){
    @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
  }
  @ </tr>
  if( needCaptcha ){
    const char *zInit = "";
    if( P("captchaseed")!=0 && eErr!=2 ){
      uSeed = strtoul(P("captchaseed"),0,10);
      zInit = P("captcha");
    }else{
      uSeed = captcha_seed();
    }
    zDecoded = captcha_decode(uSeed);
    zCaptcha = captcha_render(zDecoded);
    @ <tr>
    @  <td class="form_label">Security Code:</td>
    @  <td><input type="text" name="captcha" value="%h(zInit)" size="30">
    captcha_speakit_button(uSeed, "Speak the code");
    @  <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
    @ </tr>
    if( eErr==2 ){
      @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
    }
    @ </tr>
  }
1419
1420
1421
1422
1423
1424
1425


1426
1427
1428
1429
1430
1431
1432
  if( g.perm.Read ){
    @  <label><input type="checkbox" name="sc" %s(PCK("sc"))> \
    @  Check-ins</label><br>
  }
  if( g.perm.RdForum ){
    @  <label><input type="checkbox" name="sf" %s(PCK("sf"))> \
    @  Forum Posts</label><br>


  }
  if( g.perm.RdTkt ){
    @  <label><input type="checkbox" name="st" %s(PCK("st"))> \
    @  Ticket changes</label><br>
  }
  if( g.perm.RdWiki ){
    @  <label><input type="checkbox" name="sw" %s(PCK("sw"))> \







>
>







1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
  if( g.perm.Read ){
    @  <label><input type="checkbox" name="sc" %s(PCK("sc"))> \
    @  Check-ins</label><br>
  }
  if( g.perm.RdForum ){
    @  <label><input type="checkbox" name="sf" %s(PCK("sf"))> \
    @  Forum Posts</label><br>
    @  <label><input type="checkbox" name="sx" %s(PCK("sx"))> \
    @  Forum Edits</label><br>
  }
  if( g.perm.RdTkt ){
    @  <label><input type="checkbox" name="st" %s(PCK("st"))> \
    @  Ticket changes</label><br>
  }
  if( g.perm.RdWiki ){
    @  <label><input type="checkbox" name="sw" %s(PCK("sw"))> \
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506




1507




1508
1509
1510
1511






1512
1513
1514
1515
1516
1517

1518
1519
1520
1521
1522
1523
1524
1525



1526

1527



1528
1529

1530
1531

1532
1533
1534
1535
1536
1537

1538
1539
1540
1541
1542
1543
1544

1545















1546





1547
1548
1549
1550
1551

1552
1553
1554
1555
1556
1557
1558

1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570








1571
1572
1573
1574

1575
1576

1577
1578
1579
1580
1581

1582

1583
1584

1585
1586
1587
1588
1589
1590

1591
1592
1593
1594
1595
1596
1597
1598

1599
1600
1601

1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612

1613
1614
1615

1616
1617

1618
1619

1620
1621
1622
1623
1624





1625
1626
1627
1628
1629

1630
1631
1632
1633
1634

1635
1636

1637












1638
1639
1640
1641






1642
1643
1644
1645
1646


1647
1648
1649
1650










1651

1652
1653

1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666



1667
1668
1669





1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682


1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
  }
  @ </tr>
  @ </table>
  if( needCaptcha ){
    @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
    @ %h(zCaptcha)
    @ </pre>
    @ Enter the 8 characters above in the "Security Code" box
    @ </td></tr></table></div>
  }
  @ </form>
  fossil_free(zErr);
  style_footer();
}

/*
** Either shutdown or completely delete a subscription entry given
** by the hex value zName.  Then paint a webpage that explains that
** the entry has been removed.
*/
static void alert_unsubscribe(const char *zName){
  char *zEmail;
  zEmail = db_text(0, "SELECT semail FROM subscriber"
                      " WHERE subscriberCode=hextoblob(%Q)", zName);
  if( zEmail==0 ){
    style_header("Unsubscribe Fail");
    @ <p>Unable to locate a subscriber with the requested key</p>
  }else{
    db_multi_exec(
      "DELETE FROM subscriber WHERE subscriberCode=hextoblob(%Q)",
      zName
    );
    style_header("Unsubscribed");
    @ <p>The "%h(zEmail)" email address has been delisted.
    @ All traces of that email address have been removed</p>
  }
  style_footer();
  return;
}

/*
** WEBPAGE: alerts
**
** Edit email alert and notification settings.
**
** The subscriber is identified in either of two ways:
**
**    (1)  The name= query parameter contains the subscriberCode.




**         




**    (2)  The user is logged into an account other than "nobody" or
**         "anonymous".  In that case the notification settings
**         associated with that account can be edited without needing
**         to know the subscriber code.






*/
void alert_page(void){
  const char *zName = P("name");
  Stmt q;
  int sa, sc, sf, st, sw;
  int sdigest, sdonotcall, sverified;

  const char *ssub;
  const char *semail;
  const char *smip;
  const char *suname;
  const char *mtime;
  const char *sctime;
  int eErr = 0;
  char *zErr = 0;





  if( alert_webpages_disabled() ) return;



  login_check_credentials();
  if( !g.perm.EmailAlert ){

    login_needed(g.anon.EmailAlert);
    return;

  }
  if( zName==0 && login_is_individual() ){
    zName = db_text(0, "SELECT hex(subscriberCode) FROM subscriber"
                       " WHERE suname=%Q", g.zLogin);
  }
  if( zName==0 || !validate16(zName, -1) ){

    cgi_redirect("subscribe");
    return;
  }
  alert_submenu_common();
  if( P("submit")!=0 && cgi_csrf_safe(1) ){
    int sdonotcall = PB("sdonotcall");
    int sdigest = PB("sdigest");

    char ssub[10];















    int nsub = 0;





    if( PB("sa") )                   ssub[nsub++] = 'a';
    if( g.perm.Read && PB("sc") )    ssub[nsub++] = 'c';
    if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f';
    if( g.perm.RdTkt && PB("st") )   ssub[nsub++] = 't';
    if( g.perm.RdWiki && PB("sw") )  ssub[nsub++] = 'w';

    ssub[nsub] = 0;
    if( g.perm.Admin ){
      const char *suname = PT("suname");
      int sverified = PB("sverified");
      if( suname && suname[0]==0 ) suname = 0;
      db_multi_exec(
        "UPDATE subscriber SET"

        " sdonotcall=%d,"
        " sdigest=%d,"
        " ssub=%Q,"
        " mtime=strftime('%%s','now'),"
        " smip=%Q,"
        " suname=%Q,"
        " sverified=%d"
        " WHERE subscriberCode=hextoblob(%Q)",
        sdonotcall,
        sdigest,
        ssub,
        g.zIpAddr,








        suname,
        sverified,
        zName
      );

    }else{
      db_multi_exec(

        "UPDATE subscriber SET"
        " sdonotcall=%d,"
        " sdigest=%d,"
        " ssub=%Q,"
        " mtime=strftime('%%s','now'),"

        " smip=%Q"

        " WHERE subscriberCode=hextoblob(%Q)",
        sdonotcall,

        sdigest,
        ssub,
        g.zIpAddr,
        zName
      );
    }

  }
  if( P("delete")!=0 && cgi_csrf_safe(1) ){
    if( !PB("dodelete") ){
      eErr = 9;
      zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
                     " unsubscribe");
    }else{
      alert_unsubscribe(zName);

      return;
    }
  }

  db_prepare(&q,
    "SELECT"
    "  semail,"                       /* 0 */
    "  sverified,"                    /* 1 */
    "  sdonotcall,"                   /* 2 */
    "  sdigest,"                      /* 3 */
    "  ssub,"                         /* 4 */
    "  smip,"                         /* 5 */
    "  suname,"                       /* 6 */
    "  datetime(mtime,'unixepoch'),"  /* 7 */
    "  datetime(sctime,'unixepoch')"  /* 8 */

    " FROM subscriber WHERE subscriberCode=hextoblob(%Q)", zName);
  if( db_step(&q)!=SQLITE_ROW ){
    db_finalize(&q);

    cgi_redirect("subscribe");
    return;

  }
  style_header("Update Subscription");

  semail = db_column_text(&q, 0);
  sverified = db_column_int(&q, 1);
  sdonotcall = db_column_int(&q, 2);
  sdigest = db_column_int(&q, 3);
  ssub = db_column_text(&q, 4);





  sa = strchr(ssub,'a')!=0;
  sc = strchr(ssub,'c')!=0;
  sf = strchr(ssub,'f')!=0;
  st = strchr(ssub,'t')!=0;
  sw = strchr(ssub,'w')!=0;

  smip = db_column_text(&q, 5);
  suname = db_column_text(&q, 6);
  mtime = db_column_text(&q, 7);
  sctime = db_column_text(&q, 8);
  if( !g.perm.Admin && !sverified ){

    db_multi_exec(
      "UPDATE subscriber SET sverified=1 WHERE subscriberCode=hextoblob(%Q)",

      zName);












    @ <h1>Your email alert subscription has been verified!</h1>
    @ <p>Use the form below to update your subscription information.</p>
    @ <p>Hint:  Bookmark this page so that you can more easily update
    @ your subscription information in the future</p>






  }else{
    @ <p>Make changes to the email subscription shown below and
    @ press "Submit".</p>
  }
  form_begin(0, "%R/alerts");


  @ <input type="hidden" name="name" value="%h(zName)">
  @ <table class="subscribe">
  @ <tr>
  @  <td class="form_label">Email&nbsp;Address:</td>










  @  <td>%h(semail)</td>

  @ </tr>
  if( g.perm.Admin ){

    @ <tr>
    @  <td class='form_label'>Created:</td>
    @  <td>%h(sctime)</td>
    @ </tr>
    @ <tr>
    @  <td class='form_label'>Last Modified:</td>
    @  <td>%h(mtime)</td>
    @ </tr>
    @ <tr>
    @  <td class='form_label'>IP Address:</td>
    @  <td>%h(smip)</td>
    @ </tr>
    @ <tr>



    @  <td class="form_label">User:</td>
    @  <td><input type="text" name="suname" value="%h(suname?suname:"")" \
    @  size="30"></td>





    @ </tr>
  }
  @ <tr>
  @  <td class="form_label">Topics:</td>
  @  <td><label><input type="checkbox" name="sa" %s(sa?"checked":"")>\
  @  Announcements</label><br>
  if( g.perm.Read ){
    @  <label><input type="checkbox" name="sc" %s(sc?"checked":"")>\
    @  Check-ins</label><br>
  }
  if( g.perm.RdForum ){
    @  <label><input type="checkbox" name="sf" %s(sf?"checked":"")>\
    @  Forum Posts</label><br>


  }
  if( g.perm.RdTkt ){
    @  <label><input type="checkbox" name="st" %s(st?"checked":"")>\
    @  Ticket changes</label><br>
  }
  if( g.perm.RdWiki ){
    @  <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
    @  Wiki</label>
  }
  @ </td></tr>
  @ <tr>
  @  <td class="form_label">Delivery:</td>
  @  <td><select size="1" name="sdigest">
  @     <option value="0" %s(sdigest?"":"selected")>Individual Emails</option>
  @     <option value="1" %s(sdigest?"selected":"")>Daily Digest</option>
  @     </select></td>
  @ </tr>
#if 0
  @  <label><input type="checkbox" name="sdigest" %s(sdigest?"checked":"")>\
  @  Daily digest only</label><br>
#endif
  if( g.perm.Admin ){
    @ <tr>
    @  <td class="form_label">Admin Options:</td><td>
    @  <label><input type="checkbox" name="sdonotcall" \
    @  %s(sdonotcall?"checked":"")> Do not call</label><br>
    @  <label><input type="checkbox" name="sverified" \
    @  %s(sverified?"checked":"")>\
    @  Verified</label></td></tr>
  }
  if( eErr==9 ){
    @ <tr>
    @  <td class="form_label">Verify:</td><td>







|












|


|





|
<














|

|
>
>
>
>
|
>
>
>
>
|



>
>
>
>
>
>


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

>
|
>
>
>


>

<
>

|
|
<
<
|
>
|
<

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

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




|
<
<
<



|
>
>
>
>
>
>
>
>

|
<

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

>







|
>
|


>










|
>
|


>

<
>

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





>

<



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





>
>
|



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


>













>
>
>


|
>
>
>
>
>













>
>

















<
<
<
<




|







1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574

1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638

1639
1640
1641
1642


1643
1644
1645

1646

1647

1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678


1679


1680
1681
1682
1683
1684
1685
1686



1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700

1701
1702
1703

1704
1705




1706
1707
1708
1709

1710
1711
1712



1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744

1745
1746

1747
1748

1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763

1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875




1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
  }
  @ </tr>
  @ </table>
  if( needCaptcha ){
    @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
    @ %h(zCaptcha)
    @ </pre>
    @ Enter the 8 characters above in the "Security Code" box<br/>
    @ </td></tr></table></div>
  }
  @ </form>
  fossil_free(zErr);
  style_footer();
}

/*
** Either shutdown or completely delete a subscription entry given
** by the hex value zName.  Then paint a webpage that explains that
** the entry has been removed.
*/
static void alert_unsubscribe(int sid){
  char *zEmail;
  zEmail = db_text(0, "SELECT semail FROM subscriber"
                      " WHERE subscriberId=%d", sid);
  if( zEmail==0 ){
    style_header("Unsubscribe Fail");
    @ <p>Unable to locate a subscriber with the requested key</p>
  }else{
    db_multi_exec(
      "DELETE FROM subscriber WHERE subscriberId=%d", sid

    );
    style_header("Unsubscribed");
    @ <p>The "%h(zEmail)" email address has been delisted.
    @ All traces of that email address have been removed</p>
  }
  style_footer();
  return;
}

/*
** WEBPAGE: alerts
**
** Edit email alert and notification settings.
**
** The subscriber is identified in several ways:
**
**    (1)  The name= query parameter contains the complete subscriberCode.
**         This only happens when the user receives a verification
**         email and clicks on the link in the email.  When a
**         compilete subscriberCode is seen on the name= query parameter,
**         that constitutes verification of the email address.
**
**    (2)  The sid= query parameter contains an integer subscriberId.
**         This only works for the administrator.  It allows the
**         administrator to edit any subscription.
**         
**    (3)  The user is logged into an account other than "nobody" or
**         "anonymous".  In that case the notification settings
**         associated with that account can be edited without needing
**         to know the subscriber code.
**
**    (4)  The name= query parameter contains a 32-digit prefix of
**         subscriber code.  (Subscriber codes are normally 64 hex digits
**         in length.) This uniquely identifies the subscriber without
**         revealing the complete subscriber code, and hence without
**         verifying the email address.
*/
void alert_page(void){
  const char *zName = 0;        /* Value of the name= query parameter */
  Stmt q;                       /* For querying the database */
  int sa, sc, sf, st, sw, sx;   /* Types of notifications requested */
  int sdigest = 0, sdonotcall = 0, sverified = 0;  /* Other fields */
  int isLogin;                  /* True if logged in as an individual */
  const char *ssub = 0;         /* Subscription flags */
  const char *semail = 0;       /* Email address */
  const char *smip;             /* */
  const char *suname = 0;       /* Corresponding user.login value */
  const char *mtime;            /* */
  const char *sctime;           /* Time subscription created */
  int eErr = 0;                 /* Type of error */
  char *zErr = 0;               /* Error message text */
  int sid = 0;                  /* Subscriber ID */
  int nName;                    /* Length of zName in bytes */
  char *zHalfCode;              /* prefix of subscriberCode */

  db_begin_transaction();
  if( alert_webpages_disabled() ){
    db_commit_transaction();
    return;
  }
  login_check_credentials();
  if( !g.perm.EmailAlert ){
    db_commit_transaction();
    login_needed(g.anon.EmailAlert);

    /*NOTREACHED*/
  }
  isLogin = login_is_individual();
  zName = P("name");


  nName = zName ? (int)strlen(zName) : 0;
  if( g.perm.Admin && P("sid")!=0 ){
    sid = atoi(P("sid"));

  }

  if( sid==0 && nName>=32 ){

    sid = db_int(0,
       "SELECT CASE WHEN hex(subscriberCode) LIKE (%Q||'%%')"
       "            THEN subscriberId ELSE 0 END"
       "  FROM subscriber WHERE subscriberCode>=hextoblob(%Q)"
       " LIMIT 1", zName, zName);
  }
  if( sid==0 && isLogin ){
    sid = db_int(0, "SELECT subscriberId FROM subscriber"
                    " WHERE suname=%Q", g.zLogin);
  }
  if( sid==0 ){
    db_commit_transaction();
    cgi_redirect("subscribe");
    /*NOTREACHED*/
  }
  alert_submenu_common();
  if( P("submit")!=0 && cgi_csrf_safe(1) ){
    char newSsub[10];
    int nsub = 0;
    Blob update;

    sdonotcall = PB("sdonotcall");
    sdigest = PB("sdigest");
    semail = P("semail");
    if( PB("sa") )                   newSsub[nsub++] = 'a';
    if( g.perm.Read && PB("sc") )    newSsub[nsub++] = 'c';
    if( g.perm.RdForum && PB("sf") ) newSsub[nsub++] = 'f';
    if( g.perm.RdTkt && PB("st") )   newSsub[nsub++] = 't';
    if( g.perm.RdWiki && PB("sw") )  newSsub[nsub++] = 'w';
    if( g.perm.RdForum && PB("sx") ) newSsub[nsub++] = 'x';
    newSsub[nsub] = 0;


    ssub = newSsub;


    blob_init(&update, "UPDATE subscriber SET", -1);
    blob_append_sql(&update,
        " sdonotcall=%d,"
        " sdigest=%d,"
        " ssub=%Q,"
        " mtime=strftime('%%s','now'),"
        " smip=%Q",



        sdonotcall,
        sdigest,
        ssub,
        g.zIpAddr
    );
    if( g.perm.Admin ){
      suname = PT("suname");
      sverified = PB("sverified");
      if( suname && suname[0]==0 ) suname = 0;
      blob_append_sql(&update,
        ", suname=%Q,"
        " sverified=%d",
        suname,
        sverified

      );
    }
    if( isLogin ){

      if( semail==0 || email_address_is_valid(semail,0)==0 ){
        eErr = 8;




      }
      blob_append_sql(&update, ", semail=%Q", semail);
    }
    blob_append_sql(&update," WHERE subscriberId=%d", sid);

    if( eErr==0 ){
      db_exec_sql(blob_str(&update));
      ssub = 0;



    }
    blob_reset(&update);
  }
  if( P("delete")!=0 && cgi_csrf_safe(1) ){
    if( !PB("dodelete") ){
      eErr = 9;
      zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
                     " unsubscribe");
    }else{
      alert_unsubscribe(sid);
      db_commit_transaction();
      return; 
    }
  }
  style_header("Update Subscription");
  db_prepare(&q,
    "SELECT"
    "  semail,"                       /* 0 */
    "  sverified,"                    /* 1 */
    "  sdonotcall,"                   /* 2 */
    "  sdigest,"                      /* 3 */
    "  ssub,"                         /* 4 */
    "  smip,"                         /* 5 */
    "  suname,"                       /* 6 */
    "  datetime(mtime,'unixepoch'),"  /* 7 */
    "  datetime(sctime,'unixepoch')," /* 8 */
    "  hex(subscriberCode)"           /* 9 */
    " FROM subscriber WHERE subscriberId=%d", sid);
  if( db_step(&q)!=SQLITE_ROW ){
    db_finalize(&q);
    db_commit_transaction();
    cgi_redirect("subscribe");

    /*NOTREACHED*/
  }

  if( ssub==0 ){
    semail = db_column_text(&q, 0);

    sdonotcall = db_column_int(&q, 2);
    sdigest = db_column_int(&q, 3);
    ssub = db_column_text(&q, 4);
  }
  if( suname==0 ){
    suname = db_column_text(&q, 6);
    sverified = db_column_int(&q, 1);
  }
  sa = strchr(ssub,'a')!=0;
  sc = strchr(ssub,'c')!=0;
  sf = strchr(ssub,'f')!=0;
  st = strchr(ssub,'t')!=0;
  sw = strchr(ssub,'w')!=0;
  sx = strchr(ssub,'x')!=0;
  smip = db_column_text(&q, 5);

  mtime = db_column_text(&q, 7);
  sctime = db_column_text(&q, 8);
  if( !g.perm.Admin && !sverified ){
    if( nName==64 ){
      db_multi_exec(
        "UPDATE subscriber SET sverified=1"
        " WHERE subscriberCode=hextoblob(%Q)",
        zName);
      if( db_get_boolean("selfreg-verify",0) ){
        char *zNewCap = db_get("default-perms","u");
        db_multi_exec(
           "UPDATE user"
           "   SET cap=%Q"
           " WHERE cap='7' AND login=("
           "   SELECT suname FROM subscriber"
           "    WHERE subscriberCode=hextoblob(%Q))",
           zNewCap, zName
        );
        login_set_capabilities(zNewCap, 0);
      }
      @ <h1>Your email alert subscription has been verified!</h1>
      @ <p>Use the form below to update your subscription information.</p>
      @ <p>Hint:  Bookmark this page so that you can more easily update
      @ your subscription information in the future</p>
    }else{
      @ <h2>Your email address is unverified</h2>
      @ <p>You should have received an email message containing a link
      @ that you must visit to verify your account.  No email notifications
      @ will be sent until your email address has been verified.</p>
    }
  }else{
    @ <p>Make changes to the email subscription shown below and
    @ press "Submit".</p>
  }
  form_begin(0, "%R/alerts");
  zHalfCode = db_text("x","SELECT hex(substr(subscriberCode,1,16))"
                          "  FROM subscriber WHERE subscriberId=%d", sid);
  @ <input type="hidden" name="name" value="%h(zHalfCode)">
  @ <table class="subscribe">
  @ <tr>
  @  <td class="form_label">Email&nbsp;Address:</td>
  if( isLogin ){
    @  <td><input type="text" name="semail" value="%h(semail)" size="30">\
    if( eErr==8 ){
      @ <span class='loginError'>&larr; not a valid email address!</span>
    }else if( g.perm.Admin ){
      @ &nbsp;&nbsp;<a href="%R/announce?to=%t(semail)">\
      @ (Send a message to %h(semail))</a>\
    }
    @ </td>
  }else{
    @  <td>%h(semail)</td>
  }
  @ </tr>
  if( g.perm.Admin ){
    int uid;
    @ <tr>
    @  <td class='form_label'>Created:</td>
    @  <td>%h(sctime)</td>
    @ </tr>
    @ <tr>
    @  <td class='form_label'>Last Modified:</td>
    @  <td>%h(mtime)</td>
    @ </tr>
    @ <tr>
    @  <td class='form_label'>IP Address:</td>
    @  <td>%h(smip)</td>
    @ </tr>
    @ <tr>
    @  <td class='form_label'>Subscriber&nbsp;Code:</td>
    @  <td>%h(db_column_text(&q,9))</td>
    @ <tr>
    @  <td class="form_label">User:</td>
    @  <td><input type="text" name="suname" value="%h(suname?suname:"")" \
    @  size="30">\
    uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", suname);
    if( uid ){
      @ &nbsp;&nbsp;<a href='%R/setup_uedit?id=%d(uid)'>\
      @ (login info for %h(suname))</a>\
    }
    @ </tr>
  }
  @ <tr>
  @  <td class="form_label">Topics:</td>
  @  <td><label><input type="checkbox" name="sa" %s(sa?"checked":"")>\
  @  Announcements</label><br>
  if( g.perm.Read ){
    @  <label><input type="checkbox" name="sc" %s(sc?"checked":"")>\
    @  Check-ins</label><br>
  }
  if( g.perm.RdForum ){
    @  <label><input type="checkbox" name="sf" %s(sf?"checked":"")>\
    @  Forum Posts</label><br>
    @  <label><input type="checkbox" name="sx" %s(sx?"checked":"")>\
    @  Forum Edits</label><br>
  }
  if( g.perm.RdTkt ){
    @  <label><input type="checkbox" name="st" %s(st?"checked":"")>\
    @  Ticket changes</label><br>
  }
  if( g.perm.RdWiki ){
    @  <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
    @  Wiki</label>
  }
  @ </td></tr>
  @ <tr>
  @  <td class="form_label">Delivery:</td>
  @  <td><select size="1" name="sdigest">
  @     <option value="0" %s(sdigest?"":"selected")>Individual Emails</option>
  @     <option value="1" %s(sdigest?"selected":"")>Daily Digest</option>
  @     </select></td>
  @ </tr>




  if( g.perm.Admin ){
    @ <tr>
    @  <td class="form_label">Admin Options:</td><td>
    @  <label><input type="checkbox" name="sdonotcall" \
    @  %s(sdonotcall?"checked":"")> Do not disturb</label><br>
    @  <label><input type="checkbox" name="sverified" \
    @  %s(sverified?"checked":"")>\
    @  Verified</label></td></tr>
  }
  if( eErr==9 ){
    @ <tr>
    @  <td class="form_label">Verify:</td><td>
1724
1725
1726
1727
1728
1729
1730


1731
1732
1733
1734
1735
1736
1737
  @  <input type="submit" name="delete" value="Unsubscribe">
  @ </tr>
  @ </table>
  @ </form>
  fossil_free(zErr);
  db_finalize(&q);
  style_footer();


}

/* This is the message that gets sent to describe how to change
** or modify a subscription
*/
static const char zUnsubMsg[] = 
@ To changes your subscription settings at %s visit this link:







>
>







1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
  @  <input type="submit" name="delete" value="Unsubscribe">
  @ </tr>
  @ </table>
  @ </form>
  fossil_free(zErr);
  db_finalize(&q);
  style_footer();
  db_commit_transaction();
  return;
}

/* This is the message that gets sent to describe how to change
** or modify a subscription
*/
static const char zUnsubMsg[] = 
@ To changes your subscription settings at %s visit this link:
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771

1772
1773
1774
1775

1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
** an email address to which will be sent the unsubscribe link that
** contains the correct subscriber code.
*/
void unsubscribe_page(void){
  const char *zName = P("name");
  char *zErr = 0;
  int eErr = 0;
  unsigned int uSeed;
  const char *zDecoded;
  char *zCaptcha = 0;
  int dx;
  int bSubmit;
  const char *zEAddr;
  char *zCode = 0;


  /* If a valid subscriber code is supplied, then unsubscribe immediately.
  */
  if( zName 

   && db_exists("SELECT 1 FROM subscriber WHERE subscriberCode=hextoblob(%Q)",
                zName)
  ){
    alert_unsubscribe(zName);
    return;
  }

  /* Logged in users are redirected to the /alerts page */
  login_check_credentials();
  if( login_is_individual() ){
    cgi_redirectf("%R/alerts");







|






>




>
|
<

|







1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952

1953
1954
1955
1956
1957
1958
1959
1960
1961
** an email address to which will be sent the unsubscribe link that
** contains the correct subscriber code.
*/
void unsubscribe_page(void){
  const char *zName = P("name");
  char *zErr = 0;
  int eErr = 0;
  unsigned int uSeed = 0;
  const char *zDecoded;
  char *zCaptcha = 0;
  int dx;
  int bSubmit;
  const char *zEAddr;
  char *zCode = 0;
  int sid = 0;

  /* If a valid subscriber code is supplied, then unsubscribe immediately.
  */
  if( zName 
   && (sid = db_int(0, "SELECT subscriberId FROM subscriber"
                       " WHERE subscriberCode=hextoblob(%Q)", zName))!=0

  ){
    alert_unsubscribe(sid);
    return;
  }

  /* Logged in users are redirected to the /alerts page */
  login_check_credentials();
  if( login_is_individual() ){
    cgi_redirectf("%R/alerts");
1853
1854
1855
1856
1857
1858
1859

1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898



1899
1900
1901
1902
1903
1904
1905

1906



























1907
1908
1909
1910
1911
1912
1913
1914
1915
1916

1917
1918
1919
1920
1921
1922
1923
  @ </tr>
  uSeed = captcha_seed();
  zDecoded = captcha_decode(uSeed);
  zCaptcha = captcha_render(zDecoded);
  @ <tr>
  @  <td class="form_label">Security Code:</td>
  @  <td><input type="text" name="captcha" value="" size="30">

  @  <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
  if( eErr==2 ){
    @  <td><span class="loginError">&larr; %h(zErr)</span></td>
  }
  @ </tr>
  @ <tr>
  @  <td class="form_label">Options:</td>
  @  <td><label><input type="radio" name="dx" value="0" %s(dx?"":"checked")>\
  @  Modify subscription</label><br>
  @  <label><input type="radio" name="dx" value="1" %s(dx?"checked":"")>\
  @  Completely unsubscribe</label><br>
  @ <tr>
  @  <td></td>
  @  <td><input type="submit" name="submit" value="Submit"></td>
  @ </tr>
  @ </table>
  @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
  @ %h(zCaptcha)
  @ </pre>
  @ Enter the 8 characters above in the "Security Code" box
  @ </td></tr></table></div>
  @ </form>
  fossil_free(zErr);
  style_footer();
}

/*
** WEBPAGE: subscribers
**
** This page, accessible to administrators only,
** shows a list of email notification email addresses.
** Clicking on an email takes one to the /alerts page
** for that email where the delivery settings can be
** modified.
*/
void subscriber_list_page(void){
  Blob sql;
  Stmt q;
  sqlite3_int64 iNow;



  if( alert_webpages_disabled() ) return;
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  alert_submenu_common();

  style_header("Subscriber List");



























  blob_init(&sql, 0, 0);
  blob_append_sql(&sql,
    "SELECT hex(subscriberCode),"          /* 0 */
    "       semail,"                       /* 1 */
    "       ssub,"                         /* 2 */
    "       suname,"                       /* 3 */
    "       sverified,"                    /* 4 */
    "       sdigest,"                      /* 5 */
    "       mtime,"                        /* 6 */
    "       date(sctime,'unixepoch')"      /* 7 */

    " FROM subscriber"
  );
  if( P("only")!=0 ){
    blob_append_sql(&sql, " WHERE ssub LIKE '%%%q%%'", P("only"));
    style_submenu_element("Show All","%R/subscribers");
  }
  blob_append_sql(&sql," ORDER BY mtime DESC");







>



















|










|








>
>
>







>

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


|






|
>







2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
  @ </tr>
  uSeed = captcha_seed();
  zDecoded = captcha_decode(uSeed);
  zCaptcha = captcha_render(zDecoded);
  @ <tr>
  @  <td class="form_label">Security Code:</td>
  @  <td><input type="text" name="captcha" value="" size="30">
  captcha_speakit_button(uSeed, "Speak the code");
  @  <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
  if( eErr==2 ){
    @  <td><span class="loginError">&larr; %h(zErr)</span></td>
  }
  @ </tr>
  @ <tr>
  @  <td class="form_label">Options:</td>
  @  <td><label><input type="radio" name="dx" value="0" %s(dx?"":"checked")>\
  @  Modify subscription</label><br>
  @  <label><input type="radio" name="dx" value="1" %s(dx?"checked":"")>\
  @  Completely unsubscribe</label><br>
  @ <tr>
  @  <td></td>
  @  <td><input type="submit" name="submit" value="Submit"></td>
  @ </tr>
  @ </table>
  @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
  @ %h(zCaptcha)
  @ </pre>
  @ Enter the 8 characters above in the "Security Code" box<br/>
  @ </td></tr></table></div>
  @ </form>
  fossil_free(zErr);
  style_footer();
}

/*
** WEBPAGE: subscribers
**
** This page, accessible to administrators only,
** shows a list of subscriber email addresses.
** Clicking on an email takes one to the /alerts page
** for that email where the delivery settings can be
** modified.
*/
void subscriber_list_page(void){
  Blob sql;
  Stmt q;
  sqlite3_int64 iNow;
  int nTotal;
  int nPending;
  int nDel = 0;
  if( alert_webpages_disabled() ) return;
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  alert_submenu_common();
  style_submenu_element("Users","setup_ulist");
  style_header("Subscriber List");
  nTotal = db_int(0, "SELECT count(*) FROM subscriber");
  nPending = db_int(0, "SELECT count(*) FROM subscriber WHERE NOT sverified");
  if( nPending>0 && P("purge") && cgi_csrf_safe(0) ){
    int nNewPending;
    db_multi_exec(
       "DELETE FROM subscriber"
       " WHERE NOT sverified AND mtime<0+strftime('%%s','now','-1 day')"
    );
    nNewPending = db_int(0, "SELECT count(*) FROM subscriber"
                            " WHERE NOT sverified");
    nDel = nPending - nNewPending;
    nPending = nNewPending;
    nTotal -= nDel;
  }
  if( nPending>0 ){
    @ <h1>%,d(nTotal) Subscribers, %,d(nPending) Pending</h1>
    if( nDel==0 && 0<db_int(0,"SELECT count(*) FROM subscriber"
            " WHERE NOT sverified AND mtime<0+strftime('%%s','now','-1 day')")
    ){
      style_submenu_element("Purge Pending","subscribers?purge");
    }
  }else{
    @ <h1>%,d(nTotal) Subscribers</h1>
  }
  if( nDel>0 ){
    @ <p>*** %d(nDel) pending subscriptions deleted ***</p>
  }
  blob_init(&sql, 0, 0);
  blob_append_sql(&sql,
    "SELECT subscriberId,"                 /* 0 */
    "       semail,"                       /* 1 */
    "       ssub,"                         /* 2 */
    "       suname,"                       /* 3 */
    "       sverified,"                    /* 4 */
    "       sdigest,"                      /* 5 */
    "       mtime,"                        /* 6 */
    "       date(sctime,'unixepoch'),"     /* 7 */
    "       (SELECT uid FROM user WHERE login=subscriber.suname)" /* 8 */
    " FROM subscriber"
  );
  if( P("only")!=0 ){
    blob_append_sql(&sql, " WHERE ssub LIKE '%%%q%%'", P("only"));
    style_submenu_element("Show All","%R/subscribers");
  }
  blob_append_sql(&sql," ORDER BY mtime DESC");
1935
1936
1937
1938
1939
1940
1941


1942
1943
1944
1945
1946



1947

1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962








1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
  @ <th>Last change
  @ <th>Created
  @ </tr>
  @ </thead><tbody>
  while( db_step(&q)==SQLITE_ROW ){
    sqlite3_int64 iMtime = db_column_int64(&q, 6);
    double rAge = (iNow - iMtime)/86400.0;


    @ <tr>
    @ <td><a href='%R/alerts/%s(db_column_text(&q,0))'>\
    @ %h(db_column_text(&q,1))</a></td>
    @ <td>%h(db_column_text(&q,2))</td>
    @ <td>%s(db_column_int(&q,5)?"digest":"")</td>



    @ <td>%h(db_column_text(&q,3))</td>

    @ <td>%s(db_column_int(&q,4)?"yes":"pending")</td>
    @ <td data-sortkey='%010llx(iMtime)'>%z(human_readable_age(rAge))</td>
    @ <td>%h(db_column_text(&q,7))</td>
    @ </tr>
  }
  @ </tbody></table>
  db_finalize(&q);
  style_table_sorter();
  style_footer();
}

#if LOCAL_INTERFACE
/*
** A single event that might appear in an alert is recorded as an
** instance of the following object.








*/
struct EmailEvent {
  int type;          /* 'c', 'f', 'm', 't', 'w' */
  int needMod;       /* Pending moderator approval */
  Blob hdr;          /* Header content, for forum entries */
  Blob txt;          /* Text description to appear in an alert */
  char *zFromName;   /* Human name of the sender */
  EmailEvent *pNext; /* Next in chronological order */
};
#endif







>
>

|



>
>
>
|
>















>
>
>
>
>
>
>
>


|







2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
  @ <th>Last change
  @ <th>Created
  @ </tr>
  @ </thead><tbody>
  while( db_step(&q)==SQLITE_ROW ){
    sqlite3_int64 iMtime = db_column_int64(&q, 6);
    double rAge = (iNow - iMtime)/86400.0;
    int uid = db_column_int(&q, 8);
    const char *zUname = db_column_text(&q, 3);
    @ <tr>
    @ <td><a href='%R/alerts?sid=%d(db_column_int(&q,0))'>\
    @ %h(db_column_text(&q,1))</a></td>
    @ <td>%h(db_column_text(&q,2))</td>
    @ <td>%s(db_column_int(&q,5)?"digest":"")</td>
    if( uid ){
      @ <td><a href='%R/setup_uedit?id=%d(uid)'>%h(zUname)</a>
    }else{
      @ <td>%h(zUname)</td>
    }
    @ <td>%s(db_column_int(&q,4)?"yes":"pending")</td>
    @ <td data-sortkey='%010llx(iMtime)'>%z(human_readable_age(rAge))</td>
    @ <td>%h(db_column_text(&q,7))</td>
    @ </tr>
  }
  @ </tbody></table>
  db_finalize(&q);
  style_table_sorter();
  style_footer();
}

#if LOCAL_INTERFACE
/*
** A single event that might appear in an alert is recorded as an
** instance of the following object.
**
** type values:
**
**      c       A new check-in
**      f       An original forum post
**      x       An edit to a prior forum post
**      t       A new ticket or a change to an existing ticket
**      w       A change to a wiki page
*/
struct EmailEvent {
  int type;          /* 'c', 'f', 't', 'w', 'x' */
  int needMod;       /* Pending moderator approval */
  Blob hdr;          /* Header content, for forum entries */
  Blob txt;          /* Text description to appear in an alert */
  char *zFromName;   /* Human name of the sender */
  EmailEvent *pNext; /* Next in chronological order */
};
#endif
2001
2002
2003
2004
2005
2006
2007



2008
2009
2010
2011
2012
2013
2014
2015
  const char *zFrom;
  const char *zSub;


  /* First do non-forum post events */
  db_prepare(&q,
    "SELECT"



    " blob.uuid,"                /* 0 */
    " datetime(event.mtime),"    /* 1 */
    " coalesce(ecomment,comment)"
    "  || ' (user: ' || coalesce(euser,user,'?')"
    "  || (SELECT case when length(x)>0 then ' tags: ' || x else '' end"
    "      FROM (SELECT group_concat(substr(tagname,5), ', ') AS x"
    "              FROM tag, tagxref"
    "             WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"







>
>
>
|







2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
  const char *zFrom;
  const char *zSub;


  /* First do non-forum post events */
  db_prepare(&q,
    "SELECT"
    " CASE WHEN event.type='t'"
         " THEN (SELECT substr(tagname,5) FROM tag"
                " WHERE tagid=event.tagid AND tagname LIKE 'tkt-%%')"
         " ELSE blob.uuid END,"  /* 0 */
    " datetime(event.mtime),"    /* 1 */
    " coalesce(ecomment,comment)"
    "  || ' (user: ' || coalesce(euser,user,'?')"
    "  || (SELECT case when length(x)>0 then ' tags: ' || x else '' end"
    "      FROM (SELECT group_concat(substr(tagname,5), ', ') AS x"
    "              FROM tag, tagxref"
    "             WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
    pLast = p;
    p->type = db_column_text(&q, 3)[0];
    p->needMod = db_column_int(&q, 4);
    p->zFromName = 0;
    p->pNext = 0;
    switch( p->type ){
      case 'c':  zType = "Check-In";        break;
      case 'f':  zType = "Forum post";      break;
      case 't':  zType = "Ticket Change";   break;
      case 'w':  zType = "Wiki Edit";       break;
    }
    blob_init(&p->hdr, 0, 0);
    blob_init(&p->txt, 0, 0);
    blob_appendf(&p->txt,"== %s %s ==\n%s\n%s/info/%.20s\n",
      db_column_text(&q,1),
      zType,
      db_column_text(&q,2),
      zUrl,
      db_column_text(&q,0)
    );
    if( p->needMod ){
      blob_appendf(&p->txt,
        "** Pending moderator approval (%s/modreq) **\n",
        zUrl







|








|







2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
    pLast = p;
    p->type = db_column_text(&q, 3)[0];
    p->needMod = db_column_int(&q, 4);
    p->zFromName = 0;
    p->pNext = 0;
    switch( p->type ){
      case 'c':  zType = "Check-In";        break;
      /* case 'f':  -- forum posts omitted from this loop.  See below */
      case 't':  zType = "Ticket Change";   break;
      case 'w':  zType = "Wiki Edit";       break;
    }
    blob_init(&p->hdr, 0, 0);
    blob_init(&p->txt, 0, 0);
    blob_appendf(&p->txt,"== %s %s ==\n%s\n%s/info/%.20s\n",
      db_column_text(&q,1),
      zType,
      db_column_text(&q, 2),
      zUrl,
      db_column_text(&q,0)
    );
    if( p->needMod ){
      blob_appendf(&p->txt,
        "** Pending moderator approval (%s/modreq) **\n",
        zUrl
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083








2084


2085
2086

2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113

  /* If we reach this point, it means that forumposts exist and this
  ** is a normal email alert.  Construct full-text forum post alerts
  ** using a format that enables them to be sent as separate emails.
  */
  db_prepare(&q,
    "SELECT"
    " forumpost.fpid,"                                      /* 0 */
    " (SELECT uuid FROM blob WHERE rid=forumpost.fpid),"    /* 1 */
    " datetime(event.mtime),"                               /* 2 */
    " substr(comment,instr(comment,':')+2),"                /* 3 */








    " (SELECT uuid FROM blob WHERE rid=forumpost.firt),"    /* 4 */


    " wantalert.needMod,"                                   /* 5 */
    " coalesce(trim(substr(info,1,instr(info,'<')-1)),euser,user)"   /* 6 */

    " FROM temp.wantalert, event, forumpost"
    "      LEFT JOIN user ON (login=coalesce(euser,user))"
    " WHERE event.objid=substr(wantalert.eventId,2)+0"
    "   AND eventId GLOB 'f*'"
    "   AND forumpost.fpid=event.objid"
    " ORDER BY event.mtime"
  );
  zFrom = db_get("email-self",0);
  zSub = db_get("email-subname","");
  while( db_step(&q)==SQLITE_ROW ){
    Manifest *pPost = manifest_get(db_column_int(&q,0), CFTYPE_FORUM, 0);
    const char *zIrt;
    const char *zUuid;
    const char *zTitle;
    const char *z;
    if( pPost==0 ) continue;
    p = fossil_malloc( sizeof(EmailEvent) );
    pLast->pNext = p;
    pLast = p;
    p->type = 'f';
    p->needMod = db_column_int(&q, 5);
    z = db_column_text(&q,6);
    p->zFromName = z && z[0] ? fossil_strdup(z) : 0;
    p->pNext = 0;
    blob_init(&p->hdr, 0, 0);
    zUuid = db_column_text(&q, 1);
    zTitle = db_column_text(&q, 3);







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



















|







2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349

  /* If we reach this point, it means that forumposts exist and this
  ** is a normal email alert.  Construct full-text forum post alerts
  ** using a format that enables them to be sent as separate emails.
  */
  db_prepare(&q,
    "SELECT"
    " forumpost.fpid,"                                     /* 0: fpid */
    " (SELECT uuid FROM blob WHERE rid=forumpost.fpid),"   /* 1: hash */
    " datetime(event.mtime),"                              /* 2: date/time */
    " substr(comment,instr(comment,':')+2),"               /* 3: comment */
    " (WITH thread(fpid,fprev) AS ("
    "    SELECT fpid,fprev FROM forumpost AS tx"
    "     WHERE tx.froot=forumpost.froot),"
    "  basepid(fpid,bpid) AS ("
    "    SELECT fpid, fpid FROM thread WHERE fprev IS NULL"
    "    UNION ALL"
    "    SELECT thread.fpid, basepid.bpid FROM  basepid, thread"
    "     WHERE basepid.fpid=thread.fprev)"
    "  SELECT uuid FROM blob, basepid"
    "   WHERE basepid.fpid=forumpost.firt"
    "     AND blob.rid=basepid.bpid),"                     /* 4: in-reply-to */
    " wantalert.needMod,"                                  /* 5: moderated */
    " coalesce(display_name(info),euser,user),"            /* 6: user */
    " forumpost.fprev IS NULL"                             /* 7: is an edit */
    " FROM temp.wantalert, event, forumpost"
    "      LEFT JOIN user ON (login=coalesce(euser,user))"
    " WHERE event.objid=substr(wantalert.eventId,2)+0"
    "   AND eventId GLOB 'f*'"
    "   AND forumpost.fpid=event.objid"
    " ORDER BY event.mtime"
  );
  zFrom = db_get("email-self",0);
  zSub = db_get("email-subname","");
  while( db_step(&q)==SQLITE_ROW ){
    Manifest *pPost = manifest_get(db_column_int(&q,0), CFTYPE_FORUM, 0);
    const char *zIrt;
    const char *zUuid;
    const char *zTitle;
    const char *z;
    if( pPost==0 ) continue;
    p = fossil_malloc( sizeof(EmailEvent) );
    pLast->pNext = p;
    pLast = p;
    p->type = db_column_int(&q,7) ? 'f' : 'x';
    p->needMod = db_column_int(&q, 5);
    z = db_column_text(&q,6);
    p->zFromName = z && z[0] ? fossil_strdup(z) : 0;
    p->pNext = 0;
    blob_init(&p->hdr, 0, 0);
    zUuid = db_column_text(&q, 1);
    zTitle = db_column_text(&q, 3);
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
      if( p->needMod ){
        /* For events that require moderator approval, only send an alert
        ** if the recipient is a moderator for that type of event.  Setup
        ** and Admin users always get notified. */
        char xType = '*';
        if( strpbrk(zCap,"as")==0 ){
          switch( p->type ){
            case 'f':  xType = '5';  break;
            case 't':  xType = 'q';  break;
            case 'w':  xType = 'l';  break;
          }
          if( strchr(zCap,xType)==0 ) continue;
        }
      }else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
        /* Setup and admin users can get any notification that does not
        ** require moderation */
      }else{
        /* Other users only see the alert if they have sufficient
        ** privilege to view the event itself */
        char xType = '*';
        switch( p->type ){
          case 'c':  xType = 'o';  break;
          case 'f':  xType = '2';  break;
          case 't':  xType = 'r';  break;
          case 'w':  xType = 'j';  break;
        }
        if( strchr(zCap,xType)==0 ) continue;
      }
      if( blob_size(&p->hdr)>0 ){
        /* This alert should be sent as a separate email */
        Blob fhdr, fbody;
        blob_init(&fhdr, 0, 0);







|
|
|











|
|
|
|







2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
      if( p->needMod ){
        /* For events that require moderator approval, only send an alert
        ** if the recipient is a moderator for that type of event.  Setup
        ** and Admin users always get notified. */
        char xType = '*';
        if( strpbrk(zCap,"as")==0 ){
          switch( p->type ){
            case 'x': case 'f':  xType = '5';  break;
            case 't':            xType = 'q';  break;
            case 'w':            xType = 'l';  break;
          }
          if( strchr(zCap,xType)==0 ) continue;
        }
      }else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
        /* Setup and admin users can get any notification that does not
        ** require moderation */
      }else{
        /* Other users only see the alert if they have sufficient
        ** privilege to view the event itself */
        char xType = '*';
        switch( p->type ){
          case 'c':            xType = 'o';  break;
          case 'x': case 'f':  xType = '2';  break;
          case 't':            xType = 'r';  break;
          case 'w':            xType = 'j';  break;
        }
        if( strchr(zCap,xType)==0 ) continue;
      }
      if( blob_size(&p->hdr)>0 ){
        /* This alert should be sent as a separate email */
        Blob fhdr, fbody;
        blob_init(&fhdr, 0, 0);
2589
2590
2591
2592
2593
2594
2595

2596
2597
2598
2599
2600
2601
2602
  form_begin(0, "%R/contact_admin");
  @ <p>Enter a message to the repository administrator below:</p>
  @ <table class="subscribe">
  if( zCaptcha ){
    @ <tr>
    @  <td class="form_label">Security&nbsp;Code:</td>
    @  <td><input type="text" name="captcha" value="" size="10">

    @  <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
    @ </tr>
  }
  @ <tr>
  @  <td class="form_label">Your&nbsp;Email&nbsp;Address:</td>
  @  <td><input type="text" name="from" value="%h(PT("from"))" size="30"></td>
  @ </tr>







>







2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
  form_begin(0, "%R/contact_admin");
  @ <p>Enter a message to the repository administrator below:</p>
  @ <table class="subscribe">
  if( zCaptcha ){
    @ <tr>
    @  <td class="form_label">Security&nbsp;Code:</td>
    @  <td><input type="text" name="captcha" value="" size="10">
    captcha_speakit_button(uSeed, "Speak the code");
    @  <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
    @ </tr>
  }
  @ <tr>
  @  <td class="form_label">Your&nbsp;Email&nbsp;Address:</td>
  @  <td><input type="text" name="from" value="%h(PT("from"))" size="30"></td>
  @ </tr>
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639

2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654

2655
2656



2657








2658
2659
2660
2661
2662
2663
2664
  @   <td><input type="submit" name="submit" value="Send Message">
  @ </tr>
  @ </table>
  if( zCaptcha ){
    @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
    @ %h(zCaptcha)
    @ </pre>
    @ Enter the 8 characters above in the "Security Code" box
    @ </td></tr></table></div>
  }
  @ </form>
  style_footer();
}

/*
** Send an annoucement message described by query parameter.
** Permission to do this has already been verified.
*/
static char *alert_send_announcement(void){
  AlertSender *pSender;
  char *zErr;
  const char *zTo = PT("to");
  char *zSubject = PT("subject");
  int bAll = PB("all");
  int bAA = PB("aa");

  const char *zSub = db_get("email-subname", "[Fossil Repo]");
  int bTest2 = fossil_strcmp(P("name"),"test2")==0;
  Blob hdr, body;
  blob_init(&body, 0, 0);
  blob_init(&hdr, 0, 0);
  blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/);
  pSender = alert_sender_new(bTest2 ? "blob" : 0, 0);
  if( zTo[0] ){
    blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject);
    alert_send(pSender, &hdr, &body, 0);
  }
  if( bAll || bAA ){
    Stmt q;
    int nUsed = blob_size(&body);
    const char *zURL =  db_get("email-url",0);

    db_prepare(&q, "SELECT semail, hex(subscriberCode) FROM subscriber "
                   " WHERE sverified AND NOT sdonotcall %s",



                   bAll ? "" : " AND ssub LIKE '%a%'");








    while( db_step(&q)==SQLITE_ROW ){
      const char *zCode = db_column_text(&q, 1);
      zTo = db_column_text(&q, 0);
      blob_truncate(&hdr, 0);
      blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject);
      if( zURL ){
        blob_truncate(&body, nUsed);







|

















>











|



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







2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
  @   <td><input type="submit" name="submit" value="Send Message">
  @ </tr>
  @ </table>
  if( zCaptcha ){
    @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
    @ %h(zCaptcha)
    @ </pre>
    @ Enter the 8 characters above in the "Security Code" box<br/>
    @ </td></tr></table></div>
  }
  @ </form>
  style_footer();
}

/*
** Send an annoucement message described by query parameter.
** Permission to do this has already been verified.
*/
static char *alert_send_announcement(void){
  AlertSender *pSender;
  char *zErr;
  const char *zTo = PT("to");
  char *zSubject = PT("subject");
  int bAll = PB("all");
  int bAA = PB("aa");
  int bMods = PB("mods");
  const char *zSub = db_get("email-subname", "[Fossil Repo]");
  int bTest2 = fossil_strcmp(P("name"),"test2")==0;
  Blob hdr, body;
  blob_init(&body, 0, 0);
  blob_init(&hdr, 0, 0);
  blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/);
  pSender = alert_sender_new(bTest2 ? "blob" : 0, 0);
  if( zTo[0] ){
    blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject);
    alert_send(pSender, &hdr, &body, 0);
  }
  if( bAll || bAA || bMods ){
    Stmt q;
    int nUsed = blob_size(&body);
    const char *zURL =  db_get("email-url",0);
    if( bAll ){
      db_prepare(&q, "SELECT semail, hex(subscriberCode) FROM subscriber "
                     " WHERE sverified AND NOT sdonotcall");
    }else if( bAA ){
      db_prepare(&q, "SELECT semail, hex(subscriberCode) FROM subscriber "
                     " WHERE sverified AND NOT sdonotcall"
                     " AND ssub LIKE '%%a%%'");
    }else if( bMods ){
      db_prepare(&q,
        "SELECT semail, hex(subscriberCode)"
        "  FROM subscriber, user "
        " WHERE sverified AND NOT sdonotcall"
        "   AND suname=login"
        "   AND fullcap(cap) GLOB '*5*'");
    }
    while( db_step(&q)==SQLITE_ROW ){
      const char *zCode = db_column_text(&q, 1);
      zTo = db_column_text(&q, 0);
      blob_truncate(&hdr, 0);
      blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject);
      if( zURL ){
        blob_truncate(&body, nUsed);
2711
2712
2713
2714
2715
2716
2717
2718

2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735

2736
2737

2738
2739
2740
2741
2742
2743
2744
2745
2746



2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760



2761

2762
2763
2764
2765
2766
    if( zErr ){
      @ <h1>Internal Error</h1>
      @ <p>The following error was reported by the system:
      @ <blockquote><pre>
      @ %h(zErr)
      @ </pre></blockquote>
    }else{
      @ <p>The announcement has been sent.</p>

    }
    style_footer();    
    return;
  } else if( !alert_enabled() ){
    style_header("Cannot Send Announcement");
    @ <p>Either you have no subscribers yet, or email alerts are not yet
    @ <a href="https://fossil-scm.org/fossil/doc/trunk/www/alerts.md">set up</a>
    @ for this repository.</p>
    return;
  }

  style_header("Send Announcement");
  @ <form method="POST">
  @ <table class="subscribe">
  if( g.perm.Admin ){
    int aa = PB("aa");
    int all = PB("all");

    const char *aack = aa ? "checked" : "";
    const char *allck = all ? "checked" : "";

    @ <tr>
    @  <td class="form_label">To:</td>
    @  <td><input type="text" name="to" value="%h(PT("to"))" size="30"><br>
    @  <label><input type="checkbox" name="aa" %s(aack)> \
    @  All "announcement" subscribers</label> \
    @  <a href="%R/subscribers?only=a" target="_blank">(list)</a><br>
    @  <label><input type="checkbox" name="all" %s(allck)> \
    @  All subscribers</label> \
    @  <a href="%R/subscribers" target="_blank">(list)</a><br></td>



    @ </tr>
  }
  @ <tr>
  @  <td class="form_label">Subject:</td>
  @  <td><input type="text" name="subject" value="%h(PT("subject"))"\
  @  size="80"></td>
  @ </tr>
  @ <tr>
  @  <td class="form_label">Message:</td>
  @  <td><textarea name="msg" cols="80" rows="10" wrap="virtual">\
  @ %h(PT("msg"))</textarea>
  @ </tr>
  @ <tr>
  @   <td></td>



  @   <td><input type="submit" name="submit" value="Send Message">

  @ </tr>
  @ </table>
  @ </form>
  style_footer();
}







|
>

















>


>








|
>
>
>














>
>
>
|
>





2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
    if( zErr ){
      @ <h1>Internal Error</h1>
      @ <p>The following error was reported by the system:
      @ <blockquote><pre>
      @ %h(zErr)
      @ </pre></blockquote>
    }else{
      @ <p>The announcement has been sent.
      @ <a href="%h(PD("REQUEST_URI","/"))">Send another</a></p>
    }
    style_footer();    
    return;
  } else if( !alert_enabled() ){
    style_header("Cannot Send Announcement");
    @ <p>Either you have no subscribers yet, or email alerts are not yet
    @ <a href="https://fossil-scm.org/fossil/doc/trunk/www/alerts.md">set up</a>
    @ for this repository.</p>
    return;
  }

  style_header("Send Announcement");
  @ <form method="POST">
  @ <table class="subscribe">
  if( g.perm.Admin ){
    int aa = PB("aa");
    int all = PB("all");
    int aMod = PB("mods");
    const char *aack = aa ? "checked" : "";
    const char *allck = all ? "checked" : "";
    const char *modck = aMod ? "checked" : "";
    @ <tr>
    @  <td class="form_label">To:</td>
    @  <td><input type="text" name="to" value="%h(PT("to"))" size="30"><br>
    @  <label><input type="checkbox" name="aa" %s(aack)> \
    @  All "announcement" subscribers</label> \
    @  <a href="%R/subscribers?only=a" target="_blank">(list)</a><br>
    @  <label><input type="checkbox" name="all" %s(allck)> \
    @  All subscribers</label> \
    @  <a href="%R/subscribers" target="_blank">(list)</a><br>
    @  <label><input type="checkbox" name="mods" %s(modck)> \
    @  All moderators</label> \
    @  <a href="%R/setup_ulist?with=5" target="_blank">(list)</a><br></td>
    @ </tr>
  }
  @ <tr>
  @  <td class="form_label">Subject:</td>
  @  <td><input type="text" name="subject" value="%h(PT("subject"))"\
  @  size="80"></td>
  @ </tr>
  @ <tr>
  @  <td class="form_label">Message:</td>
  @  <td><textarea name="msg" cols="80" rows="10" wrap="virtual">\
  @ %h(PT("msg"))</textarea>
  @ </tr>
  @ <tr>
  @   <td></td>
  if( fossil_strcmp(P("name"),"test2")==0 ){
    @   <td><input type="submit" name="submit" value="Dry Run">
  }else{
    @   <td><input type="submit" name="submit" value="Send Message">
  }
  @ </tr>
  @ </table>
  @ </form>
  style_footer();
}
Changes to src/attach.c.
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
        cgi_redirectf("%R/tktview/%!S", zTktUuid);
      }else{
        cgi_redirectf("%R/wiki?name=%t", zWikiName);
      }
      return;
    }
    if( strcmp(zModAction,"approve")==0 ){
      moderation_approve(rid);
    }
  }
  style_header("Attachment Details");
  style_submenu_element("Raw", "%R/artifact/%s", zUuid);
  if(fShowContent){
    style_submenu_element("Line Numbers", "%R/ainfo/%s%s", zUuid,
                          ((zLn&&*zLn) ? "" : "?ln=0"));







|







543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
        cgi_redirectf("%R/tktview/%!S", zTktUuid);
      }else{
        cgi_redirectf("%R/wiki?name=%t", zWikiName);
      }
      return;
    }
    if( strcmp(zModAction,"approve")==0 ){
      moderation_approve('a', rid);
    }
  }
  style_header("Attachment Details");
  style_submenu_element("Raw", "%R/artifact/%s", zUuid);
  if(fShowContent){
    style_submenu_element("Line Numbers", "%R/ainfo/%s%s", zUuid,
                          ((zLn&&*zLn) ? "" : "?ln=0"));
Added src/backlink.c.






































































































































































































































































































































































































































































































































































































































































































































































































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

** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@sqlite.org
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to implement for managing backlinks and
** the "backlink" table of the repository database.
**
** A backlink is a reference in Fossil-Wiki or Markdown to some other
** object in the repository.
*/
#include "config.h"
#include "backlink.h"
#include <assert.h>


/*
** Show a graph all wiki, tickets, and check-ins that refer to object zUuid.
**
** If zLabel is not NULL and the graph is not empty, then output zLabel as
** a prefix to the graph.
*/
void render_backlink_graph(const char *zUuid, const char *zLabel){
  Blob sql;
  Stmt q;
  char *zGlob;
  zGlob = mprintf("%.5s*", zUuid);
  db_multi_exec(
     "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);\n"
     "DELETE FROM ok;\n"
     "INSERT OR IGNORE INTO ok(rid)\n"
     " SELECT CASE srctype\n"
           "  WHEN 2 THEN (SELECT rid FROM tagxref WHERE tagid=backlink.srcid\n"
                          " ORDER BY mtime DESC LIMIT 1)\n"
           "  ELSE srcid END\n"
     "   FROM backlink\n"
     "  WHERE target GLOB %Q"
     "    AND %Q GLOB (target || '*');",
     zGlob, zUuid
  );
  if( !db_exists("SELECT 1 FROM ok") ) return;
  if( zLabel ) cgi_printf("%s", zLabel);
  blob_zero(&sql);
  blob_append(&sql, timeline_query_for_www(), -1);
  blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
  db_prepare(&q, "%s", blob_sql_text(&sql));
  www_print_timeline(&q,
      TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL|TIMELINE_REFS,
                     0, 0, 0, 0, 0, 0);
  db_finalize(&q);
}

/*
** WEBPAGE: test-backlink-timeline
**
** Show a timeline of all check-ins and other events that have entries
** in the backlink table.  This is used for testing the rendering
** of the "References" section of the /info page.
*/
void backlink_timeline_page(void){
  Blob sql;
  Stmt q;

  login_check_credentials();
  if( !g.perm.Read || !g.perm.RdTkt || !g.perm.RdWiki ){
    login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
    return;
  }
  style_header("Backlink Timeline (Internal Testing Use)");
  db_multi_exec(
     "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
     "DELETE FROM ok;"
     "INSERT OR IGNORE INTO ok"
     " SELECT blob.rid FROM backlink, blob"
     "  WHERE blob.uuid BETWEEN backlink.target AND (backlink.target||'x')"
  );
  blob_zero(&sql);
  blob_append(&sql, timeline_query_for_www(), -1);
  blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
  db_prepare(&q, "%s", blob_sql_text(&sql));
  www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
                     0, 0, 0, 0, 0, 0);
  db_finalize(&q);
  style_footer();
}

/*
** WEBPAGE: test-backlinks
**
** Show a table of all backlinks.  Admin access only.
*/
void backlink_table_page(void){
  Stmt q;
  int n;
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(g.anon.Admin);
    return;
  }
  style_header("Backlink Table (Internal Testing Use)");
  n = db_int(0, "SELECT count(*) FROM backlink");
  @ <p>%d(n) backlink table entries:</p>
  db_prepare(&q,
    "SELECT target, srctype, srcid, datetime(mtime),"
    "  CASE srctype"
    "  WHEN 2 THEN (SELECT substr(tagname,6) FROM tag"
    "                WHERE tagid=srcid AND tagname GLOB 'wiki-*')"
    "  ELSE null END FROM backlink"
  );
  style_table_sorter();
  @ <table border="1" cellpadding="2" cellspacing="0" \
  @  class='sortable' data-column-types='ttt' data-init-sort='0'>
  @ <thead><tr><th> Source <th> Target <th> mtime </tr></thead>
  @ <tbody>
  while( db_step(&q)==SQLITE_ROW ){
    const char *zTarget = db_column_text(&q, 0);
    int srctype = db_column_int(&q, 1);
    int srcid = db_column_int(&q, 2);
    const char *zMtime = db_column_text(&q, 3);
    @ <tr><td><a href="%R/info/%h(zTarget)">%h(zTarget)</a>
    switch( srctype ){
      case BKLNK_COMMENT: {
        @ <td><a href="%R/info?name=rid:%d(srcid)">comment-%d(srcid)</a>
        break;
      }
      case BKLNK_TICKET: {
        @ <td><a href="%R/info?name=rid:%d(srcid)">ticket-%d(srcid)</a>
        break;
      }
      case BKLNK_WIKI: {
        const char *zName = db_column_text(&q, 4);
        @ <td><a href="%R/wiki?name=%h(zName)&p">wiki-%d(srcid)</a>
        break;
      }
      default: {
        @ <td>unknown(%d(srctype)) - %d(srcid)
        break;
      }
    }
    @ <td>%h(zMtime)</tr>
  }
  @ </tbody>
  @ </table>
  db_finalize(&q);
  style_footer();
}

/*
** Remove all prior backlinks for the wiki page given.  Then
** add new backlinks for the latest version of the wiki page.
*/
void backlink_wiki_refresh(const char *zWikiTitle){
  int tagid = wiki_tagid(zWikiTitle);
  int rid;
  Manifest *pWiki;
  if( tagid==0 ) return;
  rid = db_int(0, "SELECT rid FROM tagxref WHERE tagid=%d"
                  " ORDER BY mtime DESC LIMIT 1", tagid);
  if( rid==0 ) return;
  pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
  if( pWiki ){
    backlink_extract(pWiki->zWiki, pWiki->zMimetype, tagid, 2, pWiki->rDate,1);
    manifest_destroy(pWiki);
  }
}

/*
** Structure used to pass down state information through the
** markup formatters into the BACKLINK generator.
*/
#if INTERFACE
struct Backlink {
  int srcid;             /* srcid for the source document */
  int srctype;           /* One of BKLNK_*.  0=comment 1=ticket 2=wiki */
  double mtime;          /* mtime field for new BACKLINK table entries */
};
#endif


/*
** zTarget is a hyperlink target in some markup format.  If this
** target is a self-reference to some other object in the repository,
** then create an appropriate backlink.
*/
void backlink_create(Backlink *p, const char *zTarget, int nTarget){
  char zLink[HNAME_MAX+4];
  if( zTarget==0 ) return;
  if( nTarget<4 ) return;
  if( nTarget>=10 && strncmp(zTarget,"/info/",6)==0 ){
    zTarget += 6;
    nTarget -= 6;
  }
  if( nTarget>HNAME_MAX ) return;
  if( !validate16(zTarget, nTarget) ) return;
  memcpy(zLink, zTarget, nTarget);
  zLink[nTarget] = 0;
  canonical16(zLink, nTarget);
  db_multi_exec(
    "REPLACE INTO backlink(target,srctype,srcid,mtime)"
    "VALUES(%Q,%d,%d,%.17g)", zLink, p->srctype, p->srcid, p->mtime
  );
}

/*
** This routine is called by the markdown formatter for each hyperlink.
** If the hyperlink is a backlink, add it to the BACKLINK table.
*/
static int backlink_md_link(
  Blob *ob,         /* Write output text here (not used in this case) */
  Blob *target,     /* The hyperlink target */
  Blob *title,      /* Hyperlink title */
  Blob *content,    /* Content of the link */
  void *opaque
){
  Backlink *p = (Backlink*)opaque;
  char *zTarget = blob_buffer(target);
  int nTarget = blob_size(target);

  backlink_create(p, zTarget, nTarget);
  return 1;    
}

/* No-op routine for the rendering callbacks that we do not need */
static void mkdn_noop0(Blob *x){ return; }
static int mkdn_noop1(Blob *x){ return 1; }

/*
** Scan markdown text and add self-hyperlinks to the BACKLINK table.
*/
void markdown_extract_links(
  char *zInputText,
  Backlink *p
){
  struct mkd_renderer html_renderer = {
    /* prolog     */ (void(*)(Blob*,void*))mkdn_noop0,
    /* epilog     */ (void(*)(Blob*,void*))mkdn_noop0,
    /* blockcode  */ (void(*)(Blob*,Blob*,void*))mkdn_noop0,
    /* blockquote */ (void(*)(Blob*,Blob*,void*))mkdn_noop0,
    /* blockhtml  */ (void(*)(Blob*,Blob*,void*))mkdn_noop0,
    /* header     */ (void(*)(Blob*,Blob*,int,void*))mkdn_noop0,
    /* hrule      */ (void(*)(Blob*,void*))mkdn_noop0,
    /* list       */ (void(*)(Blob*,Blob*,int,void*))mkdn_noop0,
    /* listitem   */ (void(*)(Blob*,Blob*,int,void*))mkdn_noop0,
    /* paragraph  */ (void(*)(Blob*,Blob*,void*))mkdn_noop0,
    /* table      */ (void(*)(Blob*,Blob*,Blob*,void*))mkdn_noop0,
    /* table_cell */ (void(*)(Blob*,Blob*,int,void*))mkdn_noop0,
    /* table_row  */ (void(*)(Blob*,Blob*,int,void*))mkdn_noop0,
    /* autolink   */ (int(*)(Blob*,Blob*,enum mkd_autolink,void*))mkdn_noop1,
    /* codespan   */ (int(*)(Blob*,Blob*,int,void*))mkdn_noop1,
    /* dbl_emphas */ (int(*)(Blob*,Blob*,char,void*))mkdn_noop1,
    /* emphasis   */ (int(*)(Blob*,Blob*,char,void*))mkdn_noop1,
    /* image      */ (int(*)(Blob*,Blob*,Blob*,Blob*,void*))mkdn_noop1,
    /* linebreak  */ (int(*)(Blob*,void*))mkdn_noop1,
    /* link       */ backlink_md_link,
    /* r_html_tag */ (int(*)(Blob*,Blob*,void*))mkdn_noop1,
    /* tri_emphas */ (int(*)(Blob*,Blob*,char,void*))mkdn_noop1,
    0,  /* entity */
    0,  /* normal_text */
    "*_", /* emphasis characters */
    0   /* client data */
  };
  Blob out, in;
  html_renderer.opaque = (void*)p;
  blob_init(&out, 0, 0);
  blob_init(&in, zInputText, -1);
  markdown(&out, &in, &html_renderer);
  blob_reset(&out);
  blob_reset(&in);
}

/*
** Parse text looking for hyperlinks.  Insert references into the
** BACKLINK table.
*/
void backlink_extract(
  char *zSrc,            /* Input text from which links are extracted */
  const char *zMimetype, /* Mimetype of input.  NULL means fossil-wiki */
  int srcid,             /* srcid for the source document */
  int srctype,           /* One of BKLNK_*.  0=comment 1=ticket 2=wiki */
  double mtime,          /* mtime field for new BACKLINK table entries */
  int replaceFlag        /* True to overwrite prior BACKLINK entries */
){
  Backlink bklnk;
  if( replaceFlag ){
    db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
                  srctype, srcid);
  }
  bklnk.srcid = srcid;
  assert( ValidBklnk(srctype) );
  bklnk.srctype = srctype;
  bklnk.mtime = mtime;
  if( zMimetype==0 || strstr(zMimetype,"wiki")!=0 ){
    wiki_extract_links(zSrc, &bklnk, srctype==BKLNK_COMMENT ? WIKI_INLINE : 0);
  }else if( strstr(zMimetype,"markdown")!=0 ){
    markdown_extract_links(zSrc, &bklnk);
  }
}

/*
** COMMAND: test-backlinks
**
** Usage: %fossil test-backlinks SRCTYPE SRCID ?OPTIONS? INPUT-FILE
**
** Read the content of INPUT-FILE and pass it into the backlink_extract()
** routine.  But instead of adding backlinks to the backlink table,
** just print them on stdout.  SRCID and SRCTYPE are integers.
**
** Options:
**    --mtime DATETIME        Use an alternative date/time.  Defaults to the
**                            current date/time.
**    --mimetype TYPE         Use an alternative mimetype.
*/
void test_backlinks_cmd(void){
  const char *zMTime = find_option("mtime",0,1);
  const char *zMimetype = find_option("mimetype",0,1);
  Blob in;
  int srcid;
  int srctype;
  double mtime;

  verify_all_options();
  if( g.argc!=5 ){
    usage("SRCTYPE SRCID INPUTFILE");
  }
  srctype = atoi(g.argv[2]);
  if( srctype<0 || srctype>2 ){
    fossil_fatal("SRCTYPE should be a integer 0, 1, or 2");
  }
  srcid = atoi(g.argv[3]);
  blob_read_from_file(&in, g.argv[4], ExtFILE);
  sqlite3_open(":memory:",&g.db);
  if( zMTime==0 ) zMTime = "now";
  mtime = db_double(1721059.5,"SELECT julianday(%Q)",zMTime);
  g.fSqlPrint = 1;
  sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
  db_multi_exec(
    "CREATE TEMP TABLE backlink(target,srctype,srcid,mtime);\n"
    "CREATE TRIGGER backlink_insert BEFORE INSERT ON backlink BEGIN\n"
    "  SELECT print("
    " 'target='||quote(new.target)||"
    " ' srctype='||quote(new.srctype)||"
    " ' srcid='||quote(new.srcid)||"
    " ' mtime='||datetime(new.mtime));\n"
    "  SELECT raise(ignore);\n"
    "END;"
  );
  backlink_extract(blob_str(&in),zMimetype,srcid,srctype,mtime,0);
  blob_reset(&in);
}


/*
** COMMAND: test-wiki-relink
**
** Usage: %fossil test-wiki-relink  WIKI-PAGE-NAME
**
** Run the backlink_wiki_refresh() procedure on the wiki page
** named.  WIKI-PAGE-NAME can be a glob pattern or a prefix
** of the wiki page.
*/
void test_wiki_relink_cmd(void){
  Stmt q;
  db_find_and_open_repository(0, 0);
  if( g.argc!=3 ) usage("WIKI-PAGE-NAME");
  db_prepare(&q,
    "SELECT substr(tagname,6) FROM tag WHERE tagname GLOB 'wiki-%q*'",
    g.argv[2]
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zPage = db_column_text(&q,0);
    fossil_print("Relinking page: %s\n", zPage);
    backlink_wiki_refresh(zPage);
  }
  db_finalize(&q);
}
Changes to src/bag.c.
46
47
48
49
50
51
52






53
54
55
56
57
58
59
*/
struct Bag {
  int cnt;   /* Number of integers in the bag */
  int sz;    /* Number of slots in a[] */
  int used;  /* Number of used slots in a[] */
  int *a;    /* Hash table of integers that are in the bag */
};






#endif

/*
** Initialize a Bag structure
*/
void bag_init(Bag *p){
  memset(p, 0, sizeof(*p));







>
>
>
>
>
>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
*/
struct Bag {
  int cnt;   /* Number of integers in the bag */
  int sz;    /* Number of slots in a[] */
  int used;  /* Number of used slots in a[] */
  int *a;    /* Hash table of integers that are in the bag */
};
/*
** An expression for statically initializing a Bag instance, to be
** assigned to Bag instances at their declaration point. It has
** the same effect as passing the Bag to bag_init().
*/
#define Bag_INIT {0,0,0,0}
#endif

/*
** Initialize a Bag structure
*/
void bag_init(Bag *p){
  memset(p, 0, sizeof(*p));
Changes to src/branch.c.
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  if( isPrivate && zColor==0 ) zColor = "#fec084";
  if( zColor!=0 ){
    blob_appendf(&branch, "T *bgcolor * %F\n", zColor);
  }
  blob_appendf(&branch, "T *branch * %F\n", zBranch);
  blob_appendf(&branch, "T *sym-%F *\n", zBranch);
  if( isPrivate ){
    blob_appendf(&branch, "T +private *\n");
    noSign = 1;
  }

  /* Cancel all other symbolic tags */
  db_prepare(&q,
      "SELECT tagname FROM tagxref, tag"
      " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"







<







142
143
144
145
146
147
148

149
150
151
152
153
154
155
  if( isPrivate && zColor==0 ) zColor = "#fec084";
  if( zColor!=0 ){
    blob_appendf(&branch, "T *bgcolor * %F\n", zColor);
  }
  blob_appendf(&branch, "T *branch * %F\n", zBranch);
  blob_appendf(&branch, "T *sym-%F *\n", zBranch);
  if( isPrivate ){

    noSign = 1;
  }

  /* Cancel all other symbolic tags */
  db_prepare(&q,
      "SELECT tagname FROM tagxref, tag"
      " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
@   AND tag.tagname='branch'
@   AND event.objid=tagxref.rid
@ GROUP BY 1;
;

/* Call this routine to create the TEMP table */
static void brlist_create_temp_table(void){
  db_multi_exec(createBrlistQuery/*works-like:""*/);
}


#if INTERFACE
/*
** Allows bits in the mBplqFlags parameter to branch_prepare_list_query().
*/







|







242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
@   AND tag.tagname='branch'
@   AND event.objid=tagxref.rid
@ GROUP BY 1;
;

/* Call this routine to create the TEMP table */
static void brlist_create_temp_table(void){
  db_exec_sql(createBrlistQuery);
}


#if INTERFACE
/*
** Allows bits in the mBplqFlags parameter to branch_prepare_list_query().
*/
Changes to src/browse.c.
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
**                     TYPE=tree: use the /tree display instead
**    noreadme         Do not attempt to display the README file.
*/
void page_dir(void){
  char *zD = fossil_strdup(P("name"));
  int nD = zD ? strlen(zD)+1 : 0;
  int mxLen;
  int n;
  char *zPrefix;
  Stmt q;
  const char *zCI = P("ci");
  int rid = 0;
  char *zUuid = 0;
  Blob dirname;
  Manifest *pM = 0;







<







120
121
122
123
124
125
126

127
128
129
130
131
132
133
**                     TYPE=tree: use the /tree display instead
**    noreadme         Do not attempt to display the README file.
*/
void page_dir(void){
  char *zD = fossil_strdup(P("name"));
  int nD = zD ? strlen(zD)+1 : 0;
  int mxLen;

  char *zPrefix;
  Stmt q;
  const char *zCI = P("ci");
  int rid = 0;
  char *zUuid = 0;
  Blob dirname;
  Manifest *pM = 0;
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
    );
  }

  /* Generate a multi-column table listing the contents of zD[]
  ** directory.
  */
  mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/");
  n = db_int(1,"SELECT count(*) FROM localfiles; /*scan*/");
  if( mxLen<12 ) mxLen = 12;
  mxLen += (mxLen+9)/10;
  db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/");
  @ <div class="columns" style="columns: %d(mxLen)ex %d(n);">
  @ <ul class="browser">
  while( db_step(&q)==SQLITE_ROW ){
    const char *zFN;
    zFN = db_column_text(&q, 0);
    if( zFN[0]=='/' ){
      zFN++;
      @ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>







<



|







266
267
268
269
270
271
272

273
274
275
276
277
278
279
280
281
282
283
    );
  }

  /* Generate a multi-column table listing the contents of zD[]
  ** directory.
  */
  mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/");

  if( mxLen<12 ) mxLen = 12;
  mxLen += (mxLen+9)/10;
  db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/");
  @ <div class="columns files" style="columns: %d(mxLen)ex auto">
  @ <ul class="browser">
  while( db_step(&q)==SQLITE_ROW ){
    const char *zFN;
    zFN = db_column_text(&q, 0);
    if( zFN[0]=='/' ){
      zFN++;
      @ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
** 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 check-in. If zGlob and *zGlob then only files matching
** the given glob are computed.
*/
int compute_fileage(int vid, const char* zGlob){
  Stmt q;
  db_multi_exec(zComputeFileAgeSetup /*works-like:"constant"*/);
  db_prepare(&q, zComputeFileAgeRun  /*works-like:"constant"*/);
  db_bind_int(&q, ":ckin", vid);
  db_bind_text(&q, ":glob", zGlob && zGlob[0] ? zGlob : "*");
  db_exec(&q);
  db_finalize(&q);
  return 0;
}







|







916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
** 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 check-in. If zGlob and *zGlob then only files matching
** the given glob are computed.
*/
int compute_fileage(int vid, const char* zGlob){
  Stmt q;
  db_exec_sql(zComputeFileAgeSetup);
  db_prepare(&q, zComputeFileAgeRun  /*works-like:"constant"*/);
  db_bind_int(&q, ":ckin", vid);
  db_bind_text(&q, ":glob", zGlob && zGlob[0] ? zGlob : "*");
  db_exec(&q);
  db_finalize(&q);
  return 0;
}
Changes to src/capabilities.c.
240
241
242
243
244
245
246
247

248


249
250
251
252
253
254
255
} aCap[] = {
  { 'a', CAPCLASS_SUPER, 0,
    "Admin", "Create and delete users" },
  { 'b', CAPCLASS_WIKI|CAPCLASS_TKT, 0,
    "Attach", "Add attchments to wiki or tickets" },
  { 'c', CAPCLASS_TKT, 0,
    "Append-Tkt", "Append to existing tickets" },
  { 'd', CAPCLASS_WIKI|CAPCLASS_TKT, 0,

    "Delete", "Delete wiki or tickets" },


  { 'e', CAPCLASS_DATA, 0,
    "View-PII", "View sensitive info such as email addresses" },
  { 'f', CAPCLASS_WIKI, 0,
    "New-Wiki", "Create new wiki pages" },
  { 'g', CAPCLASS_DATA, 0,
    "Clone", "Clone the repository" },
  { 'h', CAPCLASS_OTHER, 0,







<
>
|
>
>







240
241
242
243
244
245
246

247
248
249
250
251
252
253
254
255
256
257
} aCap[] = {
  { 'a', CAPCLASS_SUPER, 0,
    "Admin", "Create and delete users" },
  { 'b', CAPCLASS_WIKI|CAPCLASS_TKT, 0,
    "Attach", "Add attchments to wiki or tickets" },
  { 'c', CAPCLASS_TKT, 0,
    "Append-Tkt", "Append to existing tickets" },

  /*
  ** d unused since fork from CVSTrac;
  ** see https://fossil-scm.org/forum/forumpost/43c78f4bef
  */
  { 'e', CAPCLASS_DATA, 0,
    "View-PII", "View sensitive info such as email addresses" },
  { 'f', CAPCLASS_WIKI, 0,
    "New-Wiki", "Create new wiki pages" },
  { 'g', CAPCLASS_DATA, 0,
    "Clone", "Clone the repository" },
  { 'h', CAPCLASS_OTHER, 0,
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

/*
** Generate a "capability summary table" that shows the major capabilities
** against the various user categories.
*/
void capability_summary(void){
  Stmt q;










  db_prepare(&q,
    "WITH t(id,seq) AS (VALUES('nobody',1),('anonymous',2),('reader',3),"
                       "('developer',4))"

    " SELECT id, fullcap(user.cap),seq,1"
    "   FROM t LEFT JOIN user ON t.id=user.login"
    " UNION ALL"


    " SELECT 'New User Default', fullcap(%Q), 10, 1"
    " UNION ALL"
    " SELECT 'Regular User', fullcap(capunion(cap)), 20, count(*) FROM user"
    " WHERE cap NOT GLOB '*[as]*' AND login NOT IN (SELECT id FROM t)"
    " UNION ALL"
    " SELECT 'Adminstrator', fullcap(capunion(cap)), 30, count(*) FROM user"
    " WHERE cap GLOB '*[as]*'"
    " ORDER BY 3 ASC",
    db_get("default-perms","")

  );
  @ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1">
  @ <tr><th>&nbsp;<th>Code<th>Forum<th>Tickets<th>Wiki\
  @ <th>Unversioned Content</th></tr>
  while( db_step(&q)==SQLITE_ROW ){
    const char *zId = db_column_text(&q, 0);
    const char *zCap = db_column_text(&q, 1);
    int n = db_column_int(&q, 3);
    int eType;
    static const char *const azType[] = { "off", "read", "write" };
    static const char *const azClass[] = { "capsumOff", "capsumRead", "capsumWrite" };


    if( n==0 ) continue;

    /* Code */
    if( db_column_int(&q,2)<10 ){
      @ <tr><th align="right"><tt>"%h(zId)"</tt></th>
    }else if( n>1 ){







>
>
>
>
>
>
>
>
>
>



>
|


>
>
|

|


|


<
>










|
>







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

/*
** Generate a "capability summary table" that shows the major capabilities
** against the various user categories.
*/
void capability_summary(void){
  Stmt q;
  CapabilityString *pCap;
  char *zSelfCap;
  char *zPubPages = db_get("public-pages",0);
  int hasPubPages = zPubPages && zPubPages[0];

  pCap = capability_add(0, db_get("default-perms","u"));
  capability_expand(pCap);
  zSelfCap = capability_string(pCap);
  capability_free(pCap);

  db_prepare(&q,
    "WITH t(id,seq) AS (VALUES('nobody',1),('anonymous',2),('reader',3),"
                       "('developer',4))"
    " SELECT id, CASE WHEN user.login='nobody' THEN user.cap"
                    " ELSE fullcap(user.cap) END,seq,1"
    "   FROM t LEFT JOIN user ON t.id=user.login"
    " UNION ALL"
    " SELECT 'Public Pages', %Q, 100, %d"
    " UNION ALL"
    " SELECT 'New User Default', %Q, 110, 1"
    " UNION ALL"
    " SELECT 'Regular User', fullcap(capunion(cap)), 200, count(*) FROM user"
    " WHERE cap NOT GLOB '*[as]*' AND login NOT IN (SELECT id FROM t)"
    " UNION ALL"
    " SELECT 'Adminstrator', fullcap(capunion(cap)), 300, count(*) FROM user"
    " WHERE cap GLOB '*[as]*'"
    " ORDER BY 3 ASC",

    zSelfCap, hasPubPages, zSelfCap
  );
  @ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1">
  @ <tr><th>&nbsp;<th>Code<th>Forum<th>Tickets<th>Wiki\
  @ <th>Unversioned Content</th></tr>
  while( db_step(&q)==SQLITE_ROW ){
    const char *zId = db_column_text(&q, 0);
    const char *zCap = db_column_text(&q, 1);
    int n = db_column_int(&q, 3);
    int eType;
    static const char *const azType[] = { "off", "read", "write" };
    static const char *const azClass[] = 
        { "capsumOff", "capsumRead", "capsumWrite" };

    if( n==0 ) continue;

    /* Code */
    if( db_column_int(&q,2)<10 ){
      @ <tr><th align="right"><tt>"%h(zId)"</tt></th>
    }else if( n>1 ){
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
      eType = 1;
    }else{
      eType = 0;
    }
    @ <td class="%s(azClass[eType])">%s(azType[eType])</td>

    /* Ticket */
    if( sqlite3_strglob("*[ascdnqtw]*",zCap)==0 ){
      eType = 2;
    }else if( sqlite3_strglob("*r*",zCap)==0 ){
      eType = 1;
    }else{
      eType = 0;
    }
    @ <td class="%s(azClass[eType])">%s(azType[eType])</td>







|







430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
      eType = 1;
    }else{
      eType = 0;
    }
    @ <td class="%s(azClass[eType])">%s(azType[eType])</td>

    /* Ticket */
    if( sqlite3_strglob("*[ascnqtw]*",zCap)==0 ){
      eType = 2;
    }else if( sqlite3_strglob("*r*",zCap)==0 ){
      eType = 1;
    }else{
      eType = 0;
    }
    @ <td class="%s(azClass[eType])">%s(azType[eType])</td>
Changes to src/captcha.c.
546
547
548
549
550
551
552


553
554

















555
556
557
558
559
560
561
  @ </pre>
  @ Enter security code shown above:
  @ <input type="hidden" name="captchaseed" value="%u(uSeed)" />
  @ <input type="text" name="captcha" size=8 />
  if( showButton ){
    @ <input type="submit" value="Submit">
  }


  @ </td></tr></table></div>
}


















/*
** WEBPAGE: test-captcha
** Test the captcha-generator by rendering the value of the name= query
** parameter using ascii-art.  If name= is omitted, show a random 16-digit
** hexadecimal number.
*/







>
>


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







546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  @ </pre>
  @ Enter security code shown above:
  @ <input type="hidden" name="captchaseed" value="%u(uSeed)" />
  @ <input type="text" name="captcha" size=8 />
  if( showButton ){
    @ <input type="submit" value="Submit">
  }
  @ <br/>\
  captcha_speakit_button(uSeed, 0);
  @ </td></tr></table></div>
}

/*
** Add a "Speak the captcha" button.
*/
void captcha_speakit_button(unsigned int uSeed, const char *zMsg){
  if( zMsg==0 ) zMsg = "Speak the text";
  @ <input type="button" value="%h(zMsg)" id="speakthetext">
  @ <script nonce="%h(style_nonce())">
  @ document.getElementById("speakthetext").onclick = function(){
  @   var audio = window.fossilAudioCaptcha \
  @ || new Audio("%R/captcha-audio/%u(uSeed)");
  @   window.fossilAudioCaptcha = audio;
  @   audio.currentTime = 0;
  @   audio.play();
  @ }
  @ </script>
}

/*
** WEBPAGE: test-captcha
** Test the captcha-generator by rendering the value of the name= query
** parameter using ascii-art.  If name= is omitted, show a random 16-digit
** hexadecimal number.
*/
606
607
608
609
610
611
612











































































  cgi_query_parameters_to_hidden();
  @ <p>Please demonstrate that you are human, not a spider or robot</p>
  captcha_generate(1);
  @ </form>
  style_footer();
  return 1;
}


















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
  cgi_query_parameters_to_hidden();
  @ <p>Please demonstrate that you are human, not a spider or robot</p>
  captcha_generate(1);
  @ </form>
  style_footer();
  return 1;
}

/*
** Generate a WAV file that reads aloud the hex digits given by
** zHex.
*/
static void captcha_wav(const char *zHex, Blob *pOut){
  int i;
  const int szWavHdr = 44;
  blob_init(pOut, 0, 0);
  blob_resize(pOut, szWavHdr);  /* Space for the WAV header */
  pOut->nUsed = szWavHdr;
  memset(pOut->aData, 0, szWavHdr);
  if( zHex==0 || zHex[0]==0 ) zHex = "0";
  for(i=0; zHex[i]; i++){
    int v = hex_digit_value(zHex[i]);
    int sz;
    int nData;
    const unsigned char *pData;
    char zSoundName[50];
    sqlite3_snprintf(sizeof(zSoundName),zSoundName,"sounds/%c.wav",
                     "0123456789abcdef"[v]);
    /* Extra silence in between letters */
    if( i>0 ){
      int nQuiet = 3000;
      blob_resize(pOut, pOut->nUsed+nQuiet);
      memset(pOut->aData+pOut->nUsed-nQuiet, 0x80, nQuiet);
    }
    pData = builtin_file(zSoundName, &sz);
    nData = sz - szWavHdr;
    blob_resize(pOut, pOut->nUsed+nData);
    memcpy(pOut->aData+pOut->nUsed-nData, pData+szWavHdr, nData);
    if( zHex[i+1]==0 ){
      int len = pOut->nUsed + 36;
      memcpy(pOut->aData, pData, szWavHdr);
      pOut->aData[4] = (char)(len&0xff);
      pOut->aData[5] = (char)((len>>8)&0xff);
      pOut->aData[6] = (char)((len>>16)&0xff);
      pOut->aData[7] = (char)((len>>24)&0xff);
      len = pOut->nUsed;
      pOut->aData[40] = (char)(len&0xff);
      pOut->aData[41] = (char)((len>>8)&0xff);
      pOut->aData[42] = (char)((len>>16)&0xff);
      pOut->aData[43] = (char)((len>>24)&0xff);
    }
  }
}

/*
** WEBPAGE: /captcha-audio
**
** Return a WAV file that pronounces the digits of the captcha that
** is determined by the seed given in the name= query parameter.
*/
void captcha_wav_page(void){
  const char *zSeed = P("name");
  const char *zDecode = captcha_decode((unsigned int)atoi(zSeed));
  Blob audio;
  captcha_wav(zDecode, &audio);
  cgi_set_content_type("audio/wav");
  cgi_set_content(&audio);
}

/*
** WEBPAGE: /test-captcha-audio
**
** Return a WAV file that pronounces the hex digits of the name=
** query parameter.
*/
void captcha_test_wav_page(void){
  const char *zSeed = P("name");
  Blob audio;
  captcha_wav(zSeed, &audio);
  cgi_set_content_type("audio/wav");
  cgi_set_content(&audio);
}
Changes to src/cgi.c.
176
177
178
179
180
181
182


183
184
185
186
187
188
189
/*
** Additional information used to form the HTTP reply
*/
static const char *zContentType = "text/html";     /* Content type of the reply */
static const char *zReplyStatus = "OK";            /* Reply status description */
static int iReplyStatus = 200;               /* Reply status code */
static Blob extraHeader = BLOB_INITIALIZER;  /* Extra header text */



/*
** Set the reply content type
*/
void cgi_set_content_type(const char *zType){
  zContentType = mprintf("%s", zType);
}







>
>







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
** Additional information used to form the HTTP reply
*/
static const char *zContentType = "text/html";     /* Content type of the reply */
static const char *zReplyStatus = "OK";            /* Reply status description */
static int iReplyStatus = 200;               /* Reply status code */
static Blob extraHeader = BLOB_INITIALIZER;  /* Extra header text */
static int rangeStart = 0;                   /* Start of Range: */
static int rangeEnd = 0;                     /* End of Range: plus 1 */

/*
** Set the reply content type
*/
void cgi_set_content_type(const char *zType){
  zContentType = mprintf("%s", zType);
}
207
208
209
210
211
212
213






214
215
216
217
218
219
220
}

/*
** Append text to the header of an HTTP reply
*/
void cgi_append_header(const char *zLine){
  blob_append(&extraHeader, zLine, -1);






}

/*
** Set a cookie by queuing up the appropriate HTTP header output. If
** !g.isHTTP, this is a no-op.
**
** Zero lifetime implies a session cookie.







>
>
>
>
>
>







209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
}

/*
** Append text to the header of an HTTP reply
*/
void cgi_append_header(const char *zLine){
  blob_append(&extraHeader, zLine, -1);
}
void cgi_printf_header(const char *zLine, ...){
  va_list ap;
  va_start(ap, zLine);
  blob_vappendf(&extraHeader, zLine, ap);
  va_end(ap);
}

/*
** Set a cookie by queuing up the appropriate HTTP header output. If
** !g.isHTTP, this is a no-op.
**
** Zero lifetime implies a session cookie.
264
265
266
267
268
269
270







271
272
273
274
275

276
277
278
279
280
281
282
  int total_size;
  if( iReplyStatus<=0 ){
    iReplyStatus = 200;
    zReplyStatus = "OK";
  }

  if( g.fullHttpReply ){







    fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
    fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
    fprintf(g.httpOut, "Connection: close\r\n");
    fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
  }else{

    fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
  }
  if( g.isConst ){
    /* isConst means that the reply is guaranteed to be invariant, even
    ** after configuration changes and/or Fossil binary recompiles. */
    fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
  }else if( etag_tag()!=0 ){







>
>
>
>
>
>
>





>







272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  int total_size;
  if( iReplyStatus<=0 ){
    iReplyStatus = 200;
    zReplyStatus = "OK";
  }

  if( g.fullHttpReply ){
    if( rangeEnd>0
     && iReplyStatus==200 
     && fossil_strcmp(P("REQUEST_METHOD"),"GET")==0
    ){
      iReplyStatus = 206;
      zReplyStatus = "Partial Content";
    }
    fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
    fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
    fprintf(g.httpOut, "Connection: close\r\n");
    fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
  }else{
    assert( rangeEnd==0 );
    fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
  }
  if( g.isConst ){
    /* isConst means that the reply is guaranteed to be invariant, even
    ** after configuration changes and/or Fossil binary recompiles. */
    fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
  }else if( etag_tag()!=0 ){
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
  */
  fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
  if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
    cgi_combine_header_and_body();
    blob_compress(&cgiContent[0], &cgiContent[0]);
  }

  if( iReplyStatus != 304 ) {
    if( is_gzippable() ){
      int i;
      gzip_begin(0);
      for( i=0; i<2; i++ ){
        int size = blob_size(&cgiContent[i]);
        if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
        blob_reset(&cgiContent[i]);
      }
      gzip_finish(&cgiContent[0]);
      fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
      fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
    }
    total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);





    fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
  }else{
    total_size = 0;
  }
  fprintf(g.httpOut, "\r\n");
  if( total_size>0 && iReplyStatus != 304
   && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
  ){
    int i, size;
    for(i=0; i<2; i++){
      size = blob_size(&cgiContent[i]);
      if( size>0 ){






        fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut);


      }
    }
  }
  fflush(g.httpOut);
  CGIDEBUG(("DONE\n"));

  /* After the webpage has been sent, do any useful background
  ** processing.
  */
  g.cgiOutput = 2;
  if( g.db!=0 && iReplyStatus==200 ){
    backoffice_check_if_needed();







|
|












>
>
>
>
>











|
>
>
>
>
>
>
|
>
>




|







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
  */
  fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
  if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
    cgi_combine_header_and_body();
    blob_compress(&cgiContent[0], &cgiContent[0]);
  }

  if( iReplyStatus!=304 ) {
    if( is_gzippable() && iReplyStatus!=206 ){
      int i;
      gzip_begin(0);
      for( i=0; i<2; i++ ){
        int size = blob_size(&cgiContent[i]);
        if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
        blob_reset(&cgiContent[i]);
      }
      gzip_finish(&cgiContent[0]);
      fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
      fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
    }
    total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
    if( iReplyStatus==206 ){
      fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n",
              rangeStart, rangeEnd-1, total_size);
      total_size = rangeEnd - rangeStart; 
    }
    fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
  }else{
    total_size = 0;
  }
  fprintf(g.httpOut, "\r\n");
  if( total_size>0 && iReplyStatus != 304
   && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
  ){
    int i, size;
    for(i=0; i<2; i++){
      size = blob_size(&cgiContent[i]);
      if( size<=rangeStart ){
        rangeStart -= size;
      }else{
        int n = size - rangeStart;
        if( n>total_size ){
          n = total_size;
        }
        fwrite(blob_buffer(&cgiContent[i])+rangeStart, 1, n, g.httpOut);
        rangeStart = 0;
        total_size -= n;
      }
    }
  }
  fflush(g.httpOut);
  CGIDEBUG(("-------- END cgi ---------\n"));

  /* After the webpage has been sent, do any useful background
  ** processing.
  */
  g.cgiOutput = 2;
  if( g.db!=0 && iReplyStatus==200 ){
    backoffice_check_if_needed();
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
  *pz = &z[i];
  *pLen -= i;
  return z;
}

/*
** The input *pz points to content that is terminated by a "\r\n"
** followed by the boundry marker zBoundry.  An extra "--" may or
** may not be appended to the boundry marker.  There are *pLen characters
** in *pz.
**
** This routine adds a "\000" to the end of the content (overwriting
** the "\r\n") and returns a pointer to the content.  The *pz input
** is adjusted to point to the first line following the boundry.
** The length of the content is stored in *pnContent.
*/
static char *get_bounded_content(
  char **pz,         /* Content taken from here */
  int *pLen,         /* Number of bytes of data in (*pz)[] */
  char *zBoundry,    /* Boundry text marking the end of content */
  int *pnContent     /* Write the size of the content here */
){
  char *z = *pz;
  int len = *pLen;
  int i;
  int nBoundry = strlen(zBoundry);
  *pnContent = len;
  for(i=0; i<len; i++){
    if( z[i]=='\n' && strncmp(zBoundry, &z[i+1], nBoundry)==0 ){
      if( i>0 && z[i-1]=='\r' ) i--;
      z[i] = 0;
      *pnContent = i;
      i += nBoundry;
      break;
    }
  }
  *pz = &z[i];
  get_line_from_string(pz, pLen);
  return z;
}







|
|




|





|





|


|



|







709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
  *pz = &z[i];
  *pLen -= i;
  return z;
}

/*
** The input *pz points to content that is terminated by a "\r\n"
** followed by the boundary marker zBoundary.  An extra "--" may or
** may not be appended to the boundary marker.  There are *pLen characters
** in *pz.
**
** This routine adds a "\000" to the end of the content (overwriting
** the "\r\n") and returns a pointer to the content.  The *pz input
** is adjusted to point to the first line following the boundary.
** The length of the content is stored in *pnContent.
*/
static char *get_bounded_content(
  char **pz,         /* Content taken from here */
  int *pLen,         /* Number of bytes of data in (*pz)[] */
  char *zBoundary,    /* Boundary text marking the end of content */
  int *pnContent     /* Write the size of the content here */
){
  char *z = *pz;
  int len = *pLen;
  int i;
  int nBoundary = strlen(zBoundary);
  *pnContent = len;
  for(i=0; i<len; i++){
    if( z[i]=='\n' && strncmp(zBoundary, &z[i+1], nBoundary)==0 ){
      if( i>0 && z[i-1]=='\r' ) i--;
      z[i] = 0;
      *pnContent = i;
      i += nBoundary;
      break;
    }
  }
  *pz = &z[i];
  get_line_from_string(pz, pLen);
  return z;
}
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
** not copied.  The calling function must not deallocate or modify
** "z" after this routine finishes or it could corrupt the parameter
** table.
*/
static void process_multipart_form_data(char *z, int len){
  char *zLine;
  int nArg, i;
  char *zBoundry;
  char *zValue;
  char *zName = 0;
  int showBytes = 0;
  char *azArg[50];

  zBoundry = get_line_from_string(&z, &len);
  if( zBoundry==0 ) return;
  while( (zLine = get_line_from_string(&z, &len))!=0 ){
    if( zLine[0]==0 ){
      int nContent = 0;
      zValue = get_bounded_content(&z, &len, zBoundry, &nContent);
      if( zName && zValue ){
        if( fossil_islower(zName[0]) ){
          cgi_set_parameter_nocopy(zName, zValue, 1);
          if( showBytes ){
            cgi_set_parameter_nocopy(mprintf("%s:bytes", zName),
                 mprintf("%d",nContent), 1);
          }







|





|
|



|







803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
** not copied.  The calling function must not deallocate or modify
** "z" after this routine finishes or it could corrupt the parameter
** table.
*/
static void process_multipart_form_data(char *z, int len){
  char *zLine;
  int nArg, i;
  char *zBoundary;
  char *zValue;
  char *zName = 0;
  int showBytes = 0;
  char *azArg[50];

  zBoundary = get_line_from_string(&z, &len);
  if( zBoundary==0 ) return;
  while( (zLine = get_line_from_string(&z, &len))!=0 ){
    if( zLine[0]==0 ){
      int nContent = 0;
      zValue = get_bounded_content(&z, &len, zBoundary, &nContent);
      if( zName && zValue ){
        if( fossil_islower(zName[0]) ){
          cgi_set_parameter_nocopy(zName, zValue, 1);
          if( showBytes ){
            cgi_set_parameter_nocopy(mprintf("%s:bytes", zName),
                 mprintf("%d",nContent), 1);
          }
1033
1034
1035
1036
1037
1038
1039

1040
1041












1042

1043
1044
1045
1046
1047
1048
1049
    zRequestUri = mprintf("%s/%s", zScriptName, z);
    cgi_set_parameter("REQUEST_URI", zRequestUri);
  }
  if( zPathInfo==0 ){
    int i, j;
    for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){}
    for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}

    cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i));
  }














  z = (char*)P("HTTP_COOKIE");
  if( z ){
    z = mprintf("%s",z);
    add_param_list(z, ';');
  }

  z = (char*)P("QUERY_STRING");







>
|

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







1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
    zRequestUri = mprintf("%s/%s", zScriptName, z);
    cgi_set_parameter("REQUEST_URI", zRequestUri);
  }
  if( zPathInfo==0 ){
    int i, j;
    for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){}
    for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
    zPathInfo = mprintf("%.*s", j-i, zRequestUri+i);
    cgi_set_parameter("PATH_INFO", zPathInfo);
  }
#ifdef FOSSIL_ENABLE_JSON
  if(strncmp("/json",zPathInfo,5)==0
     && (zPathInfo[5]==0 || zPathInfo[5]=='/')){
    /* We need to change some following behaviour depending on whether
    ** we are operating in JSON mode or not. We cannot, however, be
    ** certain whether we should/need to be in JSON mode until the
    ** PATH_INFO is set up.
    */
    g.json.isJsonMode = 1;
  }else{
    assert(!g.json.isJsonMode &&
           "Internal misconfiguration of g.json.isJsonMode");
  }
#endif
  z = (char*)P("HTTP_COOKIE");
  if( z ){
    z = mprintf("%s",z);
    add_param_list(z, ';');
  }

  z = (char*)P("QUERY_STRING");
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
  blob_zero(&g.cgiIn);
  if( len>0 && zType ){
    if( fossil_strcmp(zType, "application/x-fossil")==0 ){
      blob_read_from_channel(&g.cgiIn, g.httpIn, len);
      blob_uncompress(&g.cgiIn, &g.cgiIn);
    }
#ifdef FOSSIL_ENABLE_JSON
    else if( noJson==0 && (fossil_strcmp(zType, "application/json")==0
              || fossil_strcmp(zType,"text/plain")==0/*assume this MIGHT be JSON*/
              || fossil_strcmp(zType,"application/javascript")==0) ){
      g.json.isJsonMode = 1;
      cgi_parse_POST_JSON(g.httpIn, (unsigned int)len);
      /* FIXMEs:

      - See if fossil really needs g.cgiIn to be set for this purpose
      (i don't think it does). If it does then fill g.cgiIn and
      refactor to parse the JSON from there.

      - After parsing POST JSON, copy the "first layer" of keys/values
      to cgi_setenv(), honoring the upper-case distinction used
      in add_param_list(). However...

      - If we do that then we might get a disconnect in precedence of
      GET/POST arguments. i prefer for GET entries to take precedence
      over like-named POST entries, but in order for that to happen we
      need to process QUERY_STRING _after_ reading the POST data.
      */
      cgi_set_content_type(json_guess_content_type());
    }
#endif /* FOSSIL_ENABLE_JSON */
    else{
      blob_read_from_channel(&g.cgiIn, g.httpIn, len);
    }







|
<
|
<

|
|
<
<
<

|
<
<
|
<
<
<
<







1112
1113
1114
1115
1116
1117
1118
1119

1120

1121
1122
1123



1124
1125


1126




1127
1128
1129
1130
1131
1132
1133
  blob_zero(&g.cgiIn);
  if( len>0 && zType ){
    if( fossil_strcmp(zType, "application/x-fossil")==0 ){
      blob_read_from_channel(&g.cgiIn, g.httpIn, len);
      blob_uncompress(&g.cgiIn, &g.cgiIn);
    }
#ifdef FOSSIL_ENABLE_JSON
    else if( noJson==0 && g.json.isJsonMode!=0 

             && json_can_consume_content_type(zType)!=0 ){

      cgi_parse_POST_JSON(g.httpIn, (unsigned int)len);
      /*
       Potential TODOs:




       1) If parsing fails, immediately return an error response


       without dispatching the ostensibly-upcoming JSON API.




      */
      cgi_set_content_type(json_guess_content_type());
    }
#endif /* FOSSIL_ENABLE_JSON */
    else{
      blob_read_from_channel(&g.cgiIn, g.httpIn, len);
    }
1165
1166
1167
1168
1169
1170
1171




1172
1173
1174
1175
1176
1177
1178
      if( j<i ){
        memcpy(&aParamQP[j], &aParamQP[i], sizeof(aParamQP[j]));
      }
      j++;
    }
    nUsedQP = j;
  }





  /* Do a binary search for a matching query parameter */
  lo = 0;
  hi = nUsedQP-1;
  while( lo<=hi ){
    mid = (lo+hi)/2;
    c = fossil_strcmp(aParamQP[mid].zName, zName);







>
>
>
>







1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
      if( j<i ){
        memcpy(&aParamQP[j], &aParamQP[i], sizeof(aParamQP[j]));
      }
      j++;
    }
    nUsedQP = j;
  }

  /* Invoking with a NULL zName is just a way to cause the parameters
  ** to be sorted.  So go ahead and bail out in that case */
  if( zName==0 || zName[0]==0 ) return 0;

  /* Do a binary search for a matching query parameter */
  lo = 0;
  hi = nUsedQP-1;
  while( lo<=hi ){
    mid = (lo+hi)/2;
    c = fossil_strcmp(aParamQP[mid].zName, zName);
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
  }

  /* If no match is found and the name begins with an upper-case
  ** letter, then check to see if there is an environment variable
  ** with the given name. Handle environment variables with empty values
  ** the same as non-existent environment variables.
  */
  if( zName && fossil_isupper(zName[0]) ){
    const char *zValue = fossil_getenv(zName);
    if( zValue && zValue[0] ){
      cgi_set_parameter_nocopy(zName, zValue, 0);
      CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
      return zValue;
    }
  }







|







1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
  }

  /* If no match is found and the name begins with an upper-case
  ** letter, then check to see if there is an environment variable
  ** with the given name. Handle environment variables with empty values
  ** the same as non-existent environment variables.
  */
  if( fossil_isupper(zName[0]) ){
    const char *zValue = fossil_getenv(zName);
    if( zValue && zValue[0] ){
      cgi_set_parameter_nocopy(zName, zValue, 0);
      CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
      return zValue;
    }
  }
1312
1313
1314
1315
1316
1317
1318






























1319
1320
1321
1322






1323
1324
1325
1326
1327
1328
1329
1330
1331
1332

1333




1334


1335
1336


1337
1338
1339
1340
1341
1342
1343
    if( cgi_parameter(z2,0)==0 ) return 0;
  }
  va_end(ap);
  return 1;
}

/*






























** Print all query parameters on standard output.  Format the
** parameters as HTML.  This is used for testing and debugging.
**
** Omit the values of the cookies unless showAll is true.






*/
void cgi_print_all(int showAll, int onConsole){
  int i;
  cgi_parameter("","");  /* Force the parameters into sorted order */
  for(i=0; i<nUsedQP; i++){
    const char *zName = aParamQP[i].zName;
    if( !showAll ){
      if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue;
      if( fossil_strnicmp("fossil-",zName,7)==0 ) continue;
    }

    if( onConsole ){




      fossil_trace("%s = %s\n", zName, aParamQP[i].zValue);


    }else{
      cgi_printf("%h = %h  <br />\n", zName, aParamQP[i].zValue);


    }
  }
}

/*
** Export all untagged query parameters (but not cookies or environment
** variables) as hidden values of a form.







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


>
>
>
>
>
>

|








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







1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
    if( cgi_parameter(z2,0)==0 ) return 0;
  }
  va_end(ap);
  return 1;
}

/*
** Load all relevant environment variables into the parameter buffer.
** Invoke this routine prior to calling cgi_print_all() in order to see
** the full CGI environment.  This routine intended for debugging purposes
** only.
*/
void cgi_load_environment(void){
  /* The following is a list of environment variables that Fossil considers
  ** to be "relevant". */
  static const char *const azCgiVars[] = {
    "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "SCGI",
    "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING",
    "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHENICATION",
    "HTTP_CONNECTION", "HTTP_HOST",
    "HTTP_IF_NONE_MATCH", "HTTP_IF_MODIFIED_SINCE",
    "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED",
    "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",
    "REMOTE_USER", "REQUEST_METHOD",
    "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL",
    "HOME", "FOSSIL_HOME", "USERNAME", "USER", "FOSSIL_USER",
    "SQLITE_TMPDIR", "TMPDIR",
    "TEMP", "TMP", "FOSSIL_VFS",
    "FOSSIL_FORCE_TICKET_MODERATION", "FOSSIL_FORCE_WIKI_MODERATION",
    "FOSSIL_TCL_PATH", "TH1_DELETE_INTERP", "TH1_ENABLE_DOCS",
    "TH1_ENABLE_HOOKS", "TH1_ENABLE_TCL", "REMOTE_HOST",
  };
  int i;
  for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]);
}

/*
** Print all query parameters on standard output.
** This is used for testing and debugging.
**
** Omit the values of the cookies unless showAll is true.
**
** The eDest parameter determines where the output is shown:
**
**     eDest==0:    Rendering as HTML into the CGI reply
**     eDest==1:    Written to stderr
**     eDest==2:    Written to cgi_debug
*/
void cgi_print_all(int showAll, unsigned int eDest){
  int i;
  cgi_parameter("","");  /* Force the parameters into sorted order */
  for(i=0; i<nUsedQP; i++){
    const char *zName = aParamQP[i].zName;
    if( !showAll ){
      if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue;
      if( fossil_strnicmp("fossil-",zName,7)==0 ) continue;
    }
    switch( eDest ){
      case 0: {
        cgi_printf("%h = %h  <br />\n", zName, aParamQP[i].zValue);
        break;
      }
      case 1: {  
        fossil_trace("%s = %s\n", zName, aParamQP[i].zValue);
        break;
      }
      case 2: {
        cgi_debug("%s = %s\n", zName, aParamQP[i].zValue);
        break;
      }
    }
  }
}

/*
** Export all untagged query parameters (but not cookies or environment
** variables) as hidden values of a form.
1552
1553
1554
1555
1556
1557
1558

1559
1560
1561
1562
1563
1564
1565
  if( zIpAddr==0 ){
    zIpAddr = cgi_remote_ip(fileno(g.httpIn));
  }
  if( zIpAddr ){
    cgi_setenv("REMOTE_ADDR", zIpAddr);
    g.zIpAddr = mprintf("%s", zIpAddr);
  }


  /* Get all the optional fields that follow the first line.
  */
  while( fgets(zLine,sizeof(zLine),g.httpIn) ){
    char *zFieldName;
    char *zVal;








>







1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
  if( zIpAddr==0 ){
    zIpAddr = cgi_remote_ip(fileno(g.httpIn));
  }
  if( zIpAddr ){
    cgi_setenv("REMOTE_ADDR", zIpAddr);
    g.zIpAddr = mprintf("%s", zIpAddr);
  }


  /* Get all the optional fields that follow the first line.
  */
  while( fgets(zLine,sizeof(zLine),g.httpIn) ){
    char *zFieldName;
    char *zVal;

1597
1598
1599
1600
1601
1602
1603







1604
1605
1606
1607
1608
1609
1610
    }else if( fossil_strcmp(zFieldName,"authorization:")==0 ){
      cgi_setenv("HTTP_AUTHORIZATION", zVal);
    }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
      const char *zIpAddr = cgi_accept_forwarded_for(zVal);
      if( zIpAddr!=0 ){
        g.zIpAddr = mprintf("%s", zIpAddr);
        cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);







      }
    }
  }
  cgi_init();
  cgi_trace(0);
}








>
>
>
>
>
>
>







1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
    }else if( fossil_strcmp(zFieldName,"authorization:")==0 ){
      cgi_setenv("HTTP_AUTHORIZATION", zVal);
    }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
      const char *zIpAddr = cgi_accept_forwarded_for(zVal);
      if( zIpAddr!=0 ){
        g.zIpAddr = mprintf("%s", zIpAddr);
        cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
      }
    }else if( fossil_strcmp(zFieldName,"range:")==0 ){
      int x1 = 0;
      int x2 = 0;
      if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){
        rangeStart = x1;
        rangeEnd = x2+1;
      }
    }
  }
  cgi_init();
  cgi_trace(0);
}

2074
2075
2076
2077
2078
2079
2080




















2081
2082
2083
2084
2085
2086
2087
    return mprintf("");
  }else{
    return mprintf("%s, %d %s %02d %02d:%02d:%02d +0000",
                   azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon],
                   pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
  }
}





















/*
** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return
** a Unix epoch time. <= zero is returned on failure.
**
** Note that this won't handle all the _allowed_ HTTP formats, just the
** most popular one (the one generated by cgi_rfc822_datestamp(), actually).







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







2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
    return mprintf("");
  }else{
    return mprintf("%s, %d %s %02d %02d:%02d:%02d +0000",
                   azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon],
                   pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
  }
}

/*
** Returns an ISO8601-formatted time string suitable for debugging
** purposes.
**
** The value returned is always a string obtained from mprintf() and must
** be freed using fossil_free() to avoid a memory leak.
*/
char *cgi_iso8601_datestamp(void){
  struct tm *pTm;
  time_t now = time(0);
  pTm = gmtime(&now);
  if( pTm==0 ){
    return mprintf("");
  }else{
    return mprintf("%04d-%02d-%02d %02d:%02d:%02d",
                   pTm->tm_year+1900, pTm->tm_mon, pTm->tm_mday,
                   pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
  }
}

/*
** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return
** a Unix epoch time. <= zero is returned on failure.
**
** Note that this won't handle all the _allowed_ HTTP formats, just the
** most popular one (the one generated by cgi_rfc822_datestamp(), actually).
Changes to src/checkin.c.
1671
1672
1673
1674
1675
1676
1677








1678
1679
1680
1681
1682
1683
1684
                 " WHERE id %s ORDER BY 1",
                 p->integrateFlag ? "IN(0,-4)" : "=(-4)");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zIntegrateUuid = db_column_text(&q, 0);
    int rid = db_column_int(&q, 1);
    if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref "
        " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){








      blob_appendf(pOut, "T +closed %s\n", zIntegrateUuid);
    }
  }
  db_finalize(&q);

  if( p->azTag ){
    for(i=0; p->azTag[i]; i++){







>
>
>
>
>
>
>
>







1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
                 " WHERE id %s ORDER BY 1",
                 p->integrateFlag ? "IN(0,-4)" : "=(-4)");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zIntegrateUuid = db_column_text(&q, 0);
    int rid = db_column_int(&q, 1);
    if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref "
        " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){
#if 0
      /* Make sure the check-in manifest of the resulting merge child does not
      ** include a +close tag referring to the leaf check-in on a private
      ** branch, so as not to generate a missing artifact reference on
      ** repository clones without that private branch.  The merge command
      ** should have dropped the --integrate option, at this point. */
      assert( !content_is_private(rid) );
#endif
      blob_appendf(pOut, "T +closed %s\n", zIntegrateUuid);
    }
  }
  db_finalize(&q);

  if( p->azTag ){
    for(i=0; p->azTag[i]; i++){
2038
2039
2040
2041
2042
2043
2044


2045
2046
2047
2048
2049
2050
2051
  int nvid;              /* Blob-id of the new check-in */
  Blob comment;          /* Check-in comment */
  const char *zComment;  /* Check-in comment */
  Stmt q;                /* Various queries */
  char *zUuid;           /* UUID of the new check-in */
  int useHash = 0;       /* True to verify file status using hashing */
  int noSign = 0;        /* True to omit signing the manifest using GPG */


  int isAMerge = 0;      /* True if checking in a merge */
  int noWarningFlag = 0; /* True if skipping all warnings */
  int noPrompt = 0;      /* True if skipping all prompts */
  int forceFlag = 0;     /* Undocumented: Disables all checks */
  int forceDelta = 0;    /* Force a delta-manifest */
  int forceBaseline = 0; /* Force a baseline-manifest */
  int allowConflict = 0; /* Allow unresolve merge conflicts */







>
>







2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
  int nvid;              /* Blob-id of the new check-in */
  Blob comment;          /* Check-in comment */
  const char *zComment;  /* Check-in comment */
  Stmt q;                /* Various queries */
  char *zUuid;           /* UUID of the new check-in */
  int useHash = 0;       /* True to verify file status using hashing */
  int noSign = 0;        /* True to omit signing the manifest using GPG */
  int privateFlag = 0;   /* True if the --private option is present */
  int privateParent = 0; /* True if the parent check-in is private */
  int isAMerge = 0;      /* True if checking in a merge */
  int noWarningFlag = 0; /* True if skipping all warnings */
  int noPrompt = 0;      /* True if skipping all prompts */
  int forceFlag = 0;     /* Undocumented: Disables all checks */
  int forceDelta = 0;    /* Force a delta-manifest */
  int forceBaseline = 0; /* Force a baseline-manifest */
  int allowConflict = 0; /* Allow unresolve merge conflicts */
2075
2076
2077
2078
2079
2080
2081

2082
2083
2084
2085
2086
2087
2088
  int bRecheck = 0;      /* Repeat fork and closed-branch checks*/

  memset(&sCiInfo, 0, sizeof(sCiInfo));
  url_proxy_options();
  /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
  useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
  noSign = find_option("nosign",0,0)!=0;

  forceDelta = find_option("delta",0,0)!=0;
  forceBaseline = find_option("baseline",0,0)!=0;
  if( forceDelta && forceBaseline ){
    fossil_fatal("cannot use --delta and --baseline together");
  }
  dryRunFlag = find_option("dry-run","n",0)!=0;
  if( !dryRunFlag ){







>







2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
  int bRecheck = 0;      /* Repeat fork and closed-branch checks*/

  memset(&sCiInfo, 0, sizeof(sCiInfo));
  url_proxy_options();
  /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
  useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
  noSign = find_option("nosign",0,0)!=0;
  privateFlag = find_option("private",0,0)!=0;
  forceDelta = find_option("delta",0,0)!=0;
  forceBaseline = find_option("baseline",0,0)!=0;
  if( forceDelta && forceBaseline ){
    fossil_fatal("cannot use --delta and --baseline together");
  }
  dryRunFlag = find_option("dry-run","n",0)!=0;
  if( !dryRunFlag ){
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136

2137



2138






2139
2140
2141
2142
2143
2144
2145
    if( zTag[0]==0 ) continue;
    sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag,
                                    sizeof(char*)*(nTag+2));
    sCiInfo.azTag[nTag++] = zTag;
    sCiInfo.azTag[nTag] = 0;
  }
  zComFile = find_option("message-file", "M", 1);
  if( find_option("private",0,0) ){
    g.markPrivate = 1;
    if( sCiInfo.zBranch==0 ) sCiInfo.zBranch = "private";
    if( sCiInfo.zBrClr==0 && sCiInfo.zColor==0 ){
      sCiInfo.zBrClr = "#fec084";  /* Orange */
    }
  }
  sCiInfo.zDateOvrd = find_option("date-override",0,1);
  sCiInfo.zUserOvrd = find_option("user-override",0,1);
  db_must_be_within_tree();
  noSign = db_get_boolean("omitsign", 0)|noSign;
  if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
  useCksum = db_get_boolean("repo-cksum", 1);
  outputManifest = db_get_manifest_setting();
  verify_all_options();

  /* Get the ID of the parent manifest artifact */
  vid = db_lget_int("checkout", 0);
  if( vid==0 ){
    useCksum = 1;
    if( sCiInfo.zBranch==0 ) {
      sCiInfo.zBranch=db_get("main-branch", 0);
    }

  }else if( content_is_private(vid) ){



    g.markPrivate = 1;






  }

  /* Do not allow the creation of a new branch using an existing open
  ** branch name unless the --force flag is used */
  if( sCiInfo.zBranch!=0
   && !forceFlag
   && fossil_strcmp(sCiInfo.zBranch,"private")!=0







<
<
<
<
<
<
<













|


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







2118
2119
2120
2121
2122
2123
2124







2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
    if( zTag[0]==0 ) continue;
    sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag,
                                    sizeof(char*)*(nTag+2));
    sCiInfo.azTag[nTag++] = zTag;
    sCiInfo.azTag[nTag] = 0;
  }
  zComFile = find_option("message-file", "M", 1);







  sCiInfo.zDateOvrd = find_option("date-override",0,1);
  sCiInfo.zUserOvrd = find_option("user-override",0,1);
  db_must_be_within_tree();
  noSign = db_get_boolean("omitsign", 0)|noSign;
  if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
  useCksum = db_get_boolean("repo-cksum", 1);
  outputManifest = db_get_manifest_setting();
  verify_all_options();

  /* Get the ID of the parent manifest artifact */
  vid = db_lget_int("checkout", 0);
  if( vid==0 ){
    useCksum = 1;
    if( privateFlag==0 && sCiInfo.zBranch==0 ) {
      sCiInfo.zBranch=db_get("main-branch", 0);
    }
  }else{
    privateParent = content_is_private(vid);
  }

  /* Track the "private" status */
  g.markPrivate = privateFlag || privateParent;
  if( privateFlag && !privateParent ){
    /* Apply default branch name ("private") and color ("orange") if not
    ** specified otherwise on the command-line, and if the parent is not
    ** already private. */
    if( sCiInfo.zBranch==0 ) sCiInfo.zBranch = "private";
    if( sCiInfo.zBrClr==0 && sCiInfo.zColor==0 ) sCiInfo.zBrClr = "#fec084";
  }

  /* Do not allow the creation of a new branch using an existing open
  ** branch name unless the --force flag is used */
  if( sCiInfo.zBranch!=0
   && !forceFlag
   && fossil_strcmp(sCiInfo.zBranch,"private")!=0
Changes to src/clone.c.
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
      " VALUES('server-code', lower(hex(randomblob(20))), now());"
      "DELETE FROM config WHERE name='project-code';"
    );
    url_enable_proxy(0);
    clone_ssh_db_set_options();
    url_get_password_if_needed();
    g.xlinkClusterOnly = 1;
    nErr = client_sync(syncFlags,CONFIGSET_ALL,0);
    g.xlinkClusterOnly = 0;
    verify_cancel();
    db_end_transaction(0);
    db_close(1);
    if( nErr ){
      file_delete(g.argv[3]);
      fossil_fatal("server returned an error - clone aborted");







|







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
      " VALUES('server-code', lower(hex(randomblob(20))), now());"
      "DELETE FROM config WHERE name='project-code';"
    );
    url_enable_proxy(0);
    clone_ssh_db_set_options();
    url_get_password_if_needed();
    g.xlinkClusterOnly = 1;
    nErr = client_sync(syncFlags,CONFIGSET_ALL,0,0);
    g.xlinkClusterOnly = 0;
    verify_cancel();
    db_end_transaction(0);
    db_close(1);
    if( nErr ){
      file_delete(g.argv[3]);
      fossil_fatal("server returned an error - clone aborted");
Changes to src/config.h.
175
176
177
178
179
180
181


182
183
184
185
186
187
188

#if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION)

/*
** MSVC does not include the "stdint.h" header file until 2010.
*/
#if defined(_MSC_VER) && _MSC_VER<1600


   typedef __int32 int32_t;
   typedef unsigned __int32 uint32_t;
   typedef __int64 int64_t;
   typedef unsigned __int64 uint64_t;
#else
#  include <stdint.h>
#endif







>
>







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

#if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION)

/*
** MSVC does not include the "stdint.h" header file until 2010.
*/
#if defined(_MSC_VER) && _MSC_VER<1600
   typedef __int8 int8_t;
   typedef unsigned __int8 uint8_t;
   typedef __int32 int32_t;
   typedef unsigned __int32 uint32_t;
   typedef __int64 int64_t;
   typedef unsigned __int64 uint64_t;
#else
#  include <stdint.h>
#endif
Changes to src/configure.c.
94
95
96
97
98
99
100

101
102
103
104
105

106
107
108
109

110
111
112
113
114
115
116
  { "js",                     CONFIGSET_SKIN },
  { "logo-mimetype",          CONFIGSET_SKIN },
  { "logo-image",             CONFIGSET_SKIN },
  { "background-mimetype",    CONFIGSET_SKIN },
  { "background-image",       CONFIGSET_SKIN },
  { "timeline-block-markup",  CONFIGSET_SKIN },
  { "timeline-date-format",   CONFIGSET_SKIN },

  { "timeline-dwelltime",     CONFIGSET_SKIN },
  { "timeline-closetime",     CONFIGSET_SKIN },
  { "timeline-max-comment",   CONFIGSET_SKIN },
  { "timeline-plaintext",     CONFIGSET_SKIN },
  { "timeline-truncate-at-blank", CONFIGSET_SKIN },

  { "timeline-utc",           CONFIGSET_SKIN },
  { "adunit",                 CONFIGSET_SKIN },
  { "adunit-omit-if-admin",   CONFIGSET_SKIN },
  { "adunit-omit-if-user",    CONFIGSET_SKIN },

  { "sitemap-docidx",         CONFIGSET_SKIN },
  { "sitemap-download",       CONFIGSET_SKIN },
  { "sitemap-license",        CONFIGSET_SKIN },
  { "sitemap-contact",        CONFIGSET_SKIN },

#ifdef FOSSIL_ENABLE_TH1_DOCS
  { "th1-docs",               CONFIGSET_TH1 },







>





>




>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  { "js",                     CONFIGSET_SKIN },
  { "logo-mimetype",          CONFIGSET_SKIN },
  { "logo-image",             CONFIGSET_SKIN },
  { "background-mimetype",    CONFIGSET_SKIN },
  { "background-image",       CONFIGSET_SKIN },
  { "timeline-block-markup",  CONFIGSET_SKIN },
  { "timeline-date-format",   CONFIGSET_SKIN },
  { "timeline-default-style", CONFIGSET_SKIN },
  { "timeline-dwelltime",     CONFIGSET_SKIN },
  { "timeline-closetime",     CONFIGSET_SKIN },
  { "timeline-max-comment",   CONFIGSET_SKIN },
  { "timeline-plaintext",     CONFIGSET_SKIN },
  { "timeline-truncate-at-blank", CONFIGSET_SKIN },
  { "timeline-tslink-info",   CONFIGSET_SKIN },
  { "timeline-utc",           CONFIGSET_SKIN },
  { "adunit",                 CONFIGSET_SKIN },
  { "adunit-omit-if-admin",   CONFIGSET_SKIN },
  { "adunit-omit-if-user",    CONFIGSET_SKIN },
  { "default-csp",            CONFIGSET_SKIN },
  { "sitemap-docidx",         CONFIGSET_SKIN },
  { "sitemap-download",       CONFIGSET_SKIN },
  { "sitemap-license",        CONFIGSET_SKIN },
  { "sitemap-contact",        CONFIGSET_SKIN },

#ifdef FOSSIL_ENABLE_TH1_DOCS
  { "th1-docs",               CONFIGSET_TH1 },
141
142
143
144
145
146
147

148
149
150
151
152
153
154
  { "empty-dirs",             CONFIGSET_PROJ },
  { "allow-symlinks",         CONFIGSET_PROJ },
  { "dotfiles",               CONFIGSET_PROJ },
  { "parent-project-code",    CONFIGSET_PROJ },
  { "parent-project-name",    CONFIGSET_PROJ },
  { "hash-policy",            CONFIGSET_PROJ },
  { "comment-format",         CONFIGSET_PROJ },


#ifdef FOSSIL_ENABLE_LEGACY_MV_RM
  { "mv-rm-files",            CONFIGSET_PROJ },
#endif

  { "ticket-table",           CONFIGSET_TKT  },
  { "ticket-common",          CONFIGSET_TKT  },







>







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  { "empty-dirs",             CONFIGSET_PROJ },
  { "allow-symlinks",         CONFIGSET_PROJ },
  { "dotfiles",               CONFIGSET_PROJ },
  { "parent-project-code",    CONFIGSET_PROJ },
  { "parent-project-name",    CONFIGSET_PROJ },
  { "hash-policy",            CONFIGSET_PROJ },
  { "comment-format",         CONFIGSET_PROJ },
  { "mimetypes",              CONFIGSET_PROJ },

#ifdef FOSSIL_ENABLE_LEGACY_MV_RM
  { "mv-rm-files",            CONFIGSET_PROJ },
#endif

  { "ticket-table",           CONFIGSET_TKT  },
  { "ticket-common",          CONFIGSET_TKT  },
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
    }
    url_parse(zServer, URL_PROMPT_PW);
    if( g.url.protocol==0 ) fossil_fatal("no server URL specified");
    user_select();
    url_enable_proxy("via proxy: ");
    if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
    if( strncmp(zMethod, "push", n)==0 ){
      client_sync(0,0,(unsigned)mask);
    }else if( strncmp(zMethod, "pull", n)==0 ){
      client_sync(0,(unsigned)mask,0);
    }else{
      client_sync(0,(unsigned)mask,(unsigned)mask);
    }
  }else
  if( strncmp(zMethod, "reset", n)==0 ){
    int mask, i;
    char *zBackup;
    if( g.argc!=4 ) usage("reset AREA");
    mask = configure_name_to_mask(g.argv[3], 1);







|

|

|







815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
    }
    url_parse(zServer, URL_PROMPT_PW);
    if( g.url.protocol==0 ) fossil_fatal("no server URL specified");
    user_select();
    url_enable_proxy("via proxy: ");
    if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
    if( strncmp(zMethod, "push", n)==0 ){
      client_sync(0,0,(unsigned)mask,0);
    }else if( strncmp(zMethod, "pull", n)==0 ){
      client_sync(0,(unsigned)mask,0,0);
    }else{
      client_sync(0,(unsigned)mask,(unsigned)mask,0);
    }
  }else
  if( strncmp(zMethod, "reset", n)==0 ){
    int mask, i;
    char *zBackup;
    if( g.argc!=4 ) usage("reset AREA");
    mask = configure_name_to_mask(g.argv[3], 1);
Changes to src/content.c.
97
98
99
100
101
102
103
104


105
106
107
108
109
110
111
112
113
114
115





116
117
118
119
120
121
122
  contentCache.szTotal += blob_size(pBlob);
  p->content = *pBlob;
  blob_zero(pBlob);
  bag_insert(&contentCache.inCache, rid);
}

/*
** Clear the content cache.


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





}

/*
** Return the srcid associated with rid.  Or return 0 if rid is
** original content and not a delta.
*/
int delta_source_rid(int rid){







|
>
>

|









>
>
>
>
>







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  contentCache.szTotal += blob_size(pBlob);
  p->content = *pBlob;
  blob_zero(pBlob);
  bag_insert(&contentCache.inCache, rid);
}

/*
** Clear the content cache. If it is passed true, it
** also frees all associated memory, otherwise it may
** retain parts for future uses of the cache.
*/
void content_clear_cache(int bFreeIt){
  int i;
  for(i=0; i<contentCache.n; i++){
    blob_reset(&contentCache.a[i].content);
  }
  bag_clear(&contentCache.missing);
  bag_clear(&contentCache.available);
  bag_clear(&contentCache.inCache);
  contentCache.n = 0;
  contentCache.szTotal = 0;
  if(bFreeIt){
    fossil_free(contentCache.a);
    contentCache.a = 0;
    contentCache.nAlloc = 0;
  }
}

/*
** Return the srcid associated with rid.  Or return 0 if rid is
** original content and not a delta.
*/
int delta_source_rid(int rid){
765
766
767
768
769
770
771












772
773
774
775
776
777
778
** Make sure an artifact is public.
*/
void content_make_public(int rid){
  static Stmt s1;
  db_static_prepare(&s1,
    "DELETE FROM private WHERE rid=:rid"
  );












  db_bind_int(&s1, ":rid", rid);
  db_exec(&s1);
}

/*
** Try to change the storage of rid so that it is a delta from one
** of the artifacts given in aSrc[0]..aSrc[nSrc-1].  The aSrc[*] that







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







772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
** Make sure an artifact is public.
*/
void content_make_public(int rid){
  static Stmt s1;
  db_static_prepare(&s1,
    "DELETE FROM private WHERE rid=:rid"
  );
  db_bind_int(&s1, ":rid", rid);
  db_exec(&s1);
}

/*
** Make sure an artifact is private
*/
void content_make_private(int rid){
  static Stmt s1;
  db_static_prepare(&s1,
    "INSERT OR IGNORE INTO private(rid) VALUES(:rid)"
  );
  db_bind_int(&s1, ":rid", rid);
  db_exec(&s1);
}

/*
** Try to change the storage of rid so that it is a delta from one
** of the artifacts given in aSrc[0]..aSrc[nSrc-1].  The aSrc[*] that
Changes to src/cookies.c.
124
125
126
127
128
129
130
131



132
133
134
135
136
137
138
  int i;
  cookie_parse();
  for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
  if( zQVal==0 && (flags & COOKIE_READ)!=0 && i<cookies.nParam ){
    cgi_set_parameter_nocopy(zQP, cookies.aParam[i].zPValue, 1);
    return;
  }
  if( zQVal==0 ) zQVal = zDflt;



  if( (flags & COOKIE_WRITE)!=0
   && i<COOKIE_NPARAM
   && (i==cookies.nParam || strcmp(zQVal, cookies.aParam[i].zPValue))
  ){
    if( i==cookies.nParam ){
      cookies.aParam[i].zPName = zPName;
      cookies.nParam++;







|
>
>
>







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  int i;
  cookie_parse();
  for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
  if( zQVal==0 && (flags & COOKIE_READ)!=0 && i<cookies.nParam ){
    cgi_set_parameter_nocopy(zQP, cookies.aParam[i].zPValue, 1);
    return;
  }
  if( zQVal==0 ){
    zQVal = zDflt;
    if( flags & COOKIE_WRITE ) cgi_set_parameter_nocopy(zQP, zQVal, 1);
  }
  if( (flags & COOKIE_WRITE)!=0
   && i<COOKIE_NPARAM
   && (i==cookies.nParam || strcmp(zQVal, cookies.aParam[i].zPValue))
  ){
    if( i==cookies.nParam ){
      cookies.aParam[i].zPName = zPName;
      cookies.nParam++;
Changes to src/db.c.
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
*******************************************************************************
**
** Code for interfacing to the various databases.
**
** There are three separate database files that fossil interacts
** with:
**
**    (1)  The "user" database in ~/.fossil

**
**    (2)  The "repository" database
**
**    (3)  A local checkout database named "_FOSSIL_" or ".fslckout"
**         and located at the root of the local copy of the source tree.
**
*/







|
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
*******************************************************************************
**
** Code for interfacing to the various databases.
**
** There are three separate database files that fossil interacts
** with:
**
**    (1)  The "configdb" database in ~/.fossil or ~/.config/fossil.db
**         or in %LOCALAPPDATA%/_fossil
**
**    (2)  The "repository" database
**
**    (3)  A local checkout database named "_FOSSIL_" or ".fslckout"
**         and located at the root of the local copy of the source tree.
**
*/
651
652
653
654
655
656
657
658

659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
















684
685
686
687
688
689
690
    z = zEnd;
  }
  blob_reset(&sql);
  return rc;
}

/*
** Execute multiple SQL statements.

*/
int db_multi_exec(const char *zSql, ...){
  Blob sql;
  int rc = SQLITE_OK;
  va_list ap;
  const char *z, *zEnd;
  sqlite3_stmt *pStmt;
  blob_init(&sql, 0, 0);
  va_start(ap, zSql);
  blob_vappendf(&sql, zSql, ap);
  va_end(ap);
  z = blob_str(&sql);
  while( rc==SQLITE_OK && z[0] ){
    pStmt = 0;
    rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
    if( rc ){
      db_err("%s: {%s}", sqlite3_errmsg(g.db), z);
    }else if( pStmt ){
      db.nPrepare++;
      while( sqlite3_step(pStmt)==SQLITE_ROW ){}
      rc = sqlite3_finalize(pStmt);
      if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
    }
    z = zEnd;
  }
















  blob_reset(&sql);
  return rc;
}

/*
** Optionally make the following changes to the database if feasible and
** convenient.  Do not start a transaction for these changes, but only







|
>

|
<

<
<

<
<
<
|
<













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







652
653
654
655
656
657
658
659
660
661
662

663


664



665

666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
    z = zEnd;
  }
  blob_reset(&sql);
  return rc;
}

/*
** Execute multiple SQL statements.  The input text is executed
** directly without any formatting.
*/
int db_exec_sql(const char *z){

  int rc = SQLITE_OK;


  sqlite3_stmt *pStmt;



  const char *zEnd;

  while( rc==SQLITE_OK && z[0] ){
    pStmt = 0;
    rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
    if( rc ){
      db_err("%s: {%s}", sqlite3_errmsg(g.db), z);
    }else if( pStmt ){
      db.nPrepare++;
      while( sqlite3_step(pStmt)==SQLITE_ROW ){}
      rc = sqlite3_finalize(pStmt);
      if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
    }
    z = zEnd;
  }
  return rc;
}

/*
** Execute multiple SQL statements using printf-style formatting.
*/
int db_multi_exec(const char *zSql, ...){
  Blob sql;
  int rc;
  va_list ap;

  blob_init(&sql, 0, 0);
  va_start(ap, zSql);
  blob_vappendf(&sql, zSql, ap);
  va_end(ap);
  rc = db_exec_sql(blob_str(&sql));
  blob_reset(&sql);
  return rc;
}

/*
** Optionally make the following changes to the database if feasible and
** convenient.  Do not start a transaction for these changes, but only
1029
1030
1031
1032
1033
1034
1035


1036
1037
1038
1039
1040
1041
1042
                          db_hextoblob, 0, 0);
  sqlite3_create_function(db, "capunion", 1, SQLITE_UTF8, 0,
                          0, capability_union_step, capability_union_finalize);
  sqlite3_create_function(db, "fullcap", 1, SQLITE_UTF8, 0,
                          capability_fullcap, 0, 0);
  sqlite3_create_function(db, "find_emailaddr", 1, SQLITE_UTF8, 0,
                          alert_find_emailaddr_func, 0, 0);


}

#if USE_SEE
/*
** This is a pointer to the saved database encryption key string.
*/
static char *zSavedKey = 0;







>
>







1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
                          db_hextoblob, 0, 0);
  sqlite3_create_function(db, "capunion", 1, SQLITE_UTF8, 0,
                          0, capability_union_step, capability_union_finalize);
  sqlite3_create_function(db, "fullcap", 1, SQLITE_UTF8, 0,
                          capability_fullcap, 0, 0);
  sqlite3_create_function(db, "find_emailaddr", 1, SQLITE_UTF8, 0,
                          alert_find_emailaddr_func, 0, 0);
  sqlite3_create_function(db, "display_name", 1, SQLITE_UTF8, 0,
                          alert_display_name_func, 0, 0);
}

#if USE_SEE
/*
** This is a pointer to the saved database encryption key string.
*/
static char *zSavedKey = 0;
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
  sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
  sqlite3_create_function(
    db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
  );
  sqlite3_create_function(
    db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
  );
  if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_STMT, db_sql_trace, 0);
  db_add_aux_functions(db);
  re_add_sql_func(db);  /* The REGEXP operator */
  foci_register(db);    /* The "files_of_checkin" virtual table */
  sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
  return db;
}








|







1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
  sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
  sqlite3_create_function(
    db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
  );
  sqlite3_create_function(
    db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
  );
  if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
  db_add_aux_functions(db);
  re_add_sql_func(db);  /* The REGEXP operator */
  foci_register(db);    /* The "files_of_checkin" virtual table */
  sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
  return db;
}

1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
  Blob key;
  if( db_table_exists(zLabel,"sqlite_master") ) return;
  blob_init(&key, 0, 0);
  db_maybe_obtain_encryption_key(zDbName, &key);
  if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){
    char *zCmd = sqlite3_mprintf("ATTACH DATABASE %Q AS %Q KEY %Q",
                                 zDbName, zLabel, blob_str(&key));
    db_multi_exec(zCmd /*works-like:""*/);
    fossil_secure_zero(zCmd, strlen(zCmd));
    sqlite3_free(zCmd);
  }else{
    char *zCmd = sqlite3_mprintf("ATTACH DATABASE %Q AS %Q KEY ''",
                                 zDbName, zLabel);
    db_multi_exec(zCmd /*works-like:""*/);
    sqlite3_free(zCmd);
#if USE_SEE
    if( blob_size(&key)>0 ){
      sqlite3_key_v2(g.db, zLabel, blob_str(&key), -1);
    }
#endif
  }







|





|







1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
  Blob key;
  if( db_table_exists(zLabel,"sqlite_master") ) return;
  blob_init(&key, 0, 0);
  db_maybe_obtain_encryption_key(zDbName, &key);
  if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){
    char *zCmd = sqlite3_mprintf("ATTACH DATABASE %Q AS %Q KEY %Q",
                                 zDbName, zLabel, blob_str(&key));
    db_exec_sql(zCmd);
    fossil_secure_zero(zCmd, strlen(zCmd));
    sqlite3_free(zCmd);
  }else{
    char *zCmd = sqlite3_mprintf("ATTACH DATABASE %Q AS %Q KEY ''",
                                 zDbName, zLabel);
    db_exec_sql(zCmd);
    sqlite3_free(zCmd);
#if USE_SEE
    if( blob_size(&key)>0 ){
      sqlite3_key_v2(g.db, zLabel, blob_str(&key), -1);
    }
#endif
  }
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
    db_set_main_schemaname(g.db, zLabel);
  }else{
    db_attach(zDbName, zLabel);
  }
}

/*
** Close the per-user database file in ~/.fossil
*/
void db_close_config(){
  int iSlot = db_database_slot("configdb");
  if( iSlot>0 ){
    db_detach("configdb");
  }else if( g.dbConfig ){
    sqlite3_wal_checkpoint(g.dbConfig, 0);







|







1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
    db_set_main_schemaname(g.db, zLabel);
  }else{
    db_attach(zDbName, zLabel);
  }
}

/*
** Close the per-user configuration database file
*/
void db_close_config(){
  int iSlot = db_database_slot("configdb");
  if( iSlot>0 ){
    db_detach("configdb");
  }else if( g.dbConfig ){
    sqlite3_wal_checkpoint(g.dbConfig, 0);
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404


1405





1406

1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420

1421
1422
1423
1424
1425

1426







1427



1428









1429


1430



1431
1432
1433
1434

1435
1436
1437
1438
1439
1440
1441
1442
1443
1444









1445
1446























1447





1448


1449
1450
1451
1452
1453
1454
1455
1456
1457
    return;
  }
  fossil_free(g.zConfigDbName);
  g.zConfigDbName = 0;
}

/*
** Open the user database in "~/.fossil".  Create the database anew if
** it does not already exist.
**
** If the useAttach flag is 0 (the usual case) then the user database is
** opened on a separate database connection g.dbConfig.  This prevents
** the ~/.fossil database from becoming locked on long check-in or sync
** operations which hold an exclusive transaction.  In a few cases, though,
** it is convenient for the ~/.fossil to be attached to the main database
** connection so that we can join between the various databases.  In that
** case, invoke this routine with useAttach as 1.
*/
int db_open_config(int useAttach, int isOptional){
  char *zDbName;
  char *zHome;
  if( g.zConfigDbName ){
    int alreadyAttached = db_database_slot("configdb")>0;
    if( useAttach==alreadyAttached ) return 1; /* Already open. */
    db_close_config();
  }


  zHome = fossil_getenv("FOSSIL_HOME");





#if defined(_WIN32) || defined(__CYGWIN__)

  if( zHome==0 ){
    zHome = fossil_getenv("LOCALAPPDATA");
    if( zHome==0 ){
      zHome = fossil_getenv("APPDATA");
      if( zHome==0 ){
        zHome = fossil_getenv("USERPROFILE");
        if( zHome==0 ){
          char *zDrive = fossil_getenv("HOMEDRIVE");
          char *zPath = fossil_getenv("HOMEPATH");
          if( zDrive && zPath ) zHome = mprintf("%s%s", zDrive, zPath);
        }
      }
    }
  }

  if( zHome==0 ){
    if( isOptional ) return 0;
    fossil_panic("cannot locate home directory - please set the "
                 "FOSSIL_HOME, LOCALAPPDATA, APPDATA, USERPROFILE, "
                 "or HOMEDRIVE / HOMEPATH environment variables");

  }







#else



  if( zHome==0 ){









    zHome = fossil_getenv("HOME");


  }



  if( zHome==0 ){
    if( isOptional ) return 0;
    fossil_panic("cannot locate home directory - please set the "
                 "FOSSIL_HOME or HOME environment variables");

  }
#endif
  if( file_isdir(zHome, ExtFILE)!=1 ){
    if( isOptional ) return 0;
    fossil_panic("invalid home directory: %s", zHome);
  }
#if defined(_WIN32) || defined(__CYGWIN__)
  /* . filenames give some window systems problems and many apps problems */
  zDbName = mprintf("%//_fossil", zHome);
#else









  zDbName = mprintf("%s/.fossil", zHome);
#endif























  if( file_size(zDbName, ExtFILE)<1024*3 ){





    if( file_access(zHome, W_OK) ){


      if( isOptional ) return 0;
      fossil_panic("home directory %s must be writeable", zHome);
    }
    db_init_database(zDbName, zConfigSchema, (char*)0);
  }
  if( file_access(zDbName, W_OK) ){
    if( isOptional ) return 0;
    fossil_panic("configuration file %s must be writeable", zDbName);
  }







|
|

|
<
<
<
<
<
<

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

>














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

>
>
>


|
|
>

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

>
>
>
>
>
|
>
>

|







1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402






1403
1404

1405
1406
1407


1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436

1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473




1474


1475

1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
    return;
  }
  fossil_free(g.zConfigDbName);
  g.zConfigDbName = 0;
}

/*
** Compute the name of the configuration database.  If unable to find the
** database, return 0 if isOptional is true, or panic if isOptional is false.
**
** Space to hold the result comes from fossil_malloc().






*/
static char *db_configdb_name(int isOptional){

  char *zHome;        /* Home directory */
  char *zDbName;      /* Name of the database file */




  /* On Windows, look for these directories, in order:
  **
  **    FOSSIL_HOME
  **    LOCALAPPDATA
  **    APPDATA
  **    USERPROFILE
  **    HOMEDRIVE HOMEPATH
  */
#if defined(_WIN32) || defined(__CYGWIN__)
  zHome = fossil_getenv("FOSSIL_HOME");
  if( zHome==0 ){
    zHome = fossil_getenv("LOCALAPPDATA");
    if( zHome==0 ){
      zHome = fossil_getenv("APPDATA");
      if( zHome==0 ){
        zHome = fossil_getenv("USERPROFILE");
        if( zHome==0 ){
          char *zDrive = fossil_getenv("HOMEDRIVE");
          char *zPath = fossil_getenv("HOMEPATH");
          if( zDrive && zPath ) zHome = mprintf("%s%s", zDrive, zPath);
        }
      }
    }
  }
  zDbName = mprintf("%//_fossil", zHome);
  fossil_free(zHome);
  return zDbName;


#else /* if unix */
  char *zXdgHome;

  /* For unix. a 5-step algorithm is used.
  ** See ../www/tech_overview.wiki for discussion.
  **
  ** Step 1:  If FOSSIL_HOME exists -> $FOSSIL_HOME/.fossil
  */
  zHome = fossil_getenv("FOSSIL_HOME");
  if( zHome!=0 ) return mprintf("%s/.fossil", zHome);

  /* Step 2:  If HOME exists and file $HOME/.fossil exists -> $HOME/.fossil
  */
  zHome = fossil_getenv("HOME");
  if( zHome ){
    zDbName = mprintf("%s/.fossil", zHome);
    if( file_size(zDbName, ExtFILE)>1024*3 ){
      return zDbName;
    }
    fossil_free(zDbName);
  }

  /* Step 3: if XDG_CONFIG_HOME exists -> $XDG_CONFIG_HOME/fossil.db
  */
  zXdgHome = fossil_getenv("XDG_CONFIG_HOME");
  if( zXdgHome!=0 ){
    return mprintf("%s/fossil.db", zXdgHome);
  }

  /* The HOME variable is required in order to continue.
  */
  if( zHome==0 ){
    if( isOptional ) return 0;
    fossil_panic("cannot locate home directory - please set one of the "
                 "FOSSIL_HOME, XDG_CONFIG_HOME, or HOME environment "
                 "variables");
  }







  /* Step 4: If $HOME/.config is a directory -> $HOME/.config/fossil.db

  */
  zXdgHome = mprintf("%s/.config", zHome);
  if( file_isdir(zXdgHome, ExtFILE)==1 ){
    fossil_free(zXdgHome);
    return mprintf("%s/.config/fossil.db", zHome);
  }

  /* Step 5: Otherwise -> $HOME/.fossil
  */
  return mprintf("%s/.fossil", zHome);
#endif /* unix */
}

/*
** Open the configuration database.  Create the database anew if
** it does not already exist.
**
** If the useAttach flag is 0 (the usual case) then the configuration
** database is opened on a separate database connection g.dbConfig.
** This prevents the database from becoming locked on long check-in or sync
** operations which hold an exclusive transaction.  In a few cases, though,
** it is convenient for the database to be attached to the main database
** connection so that we can join between the various databases.  In that
** case, invoke this routine with useAttach as 1.
*/
int db_open_config(int useAttach, int isOptional){
  char *zDbName;
  if( g.zConfigDbName ){
    int alreadyAttached = db_database_slot("configdb")>0;
    if( useAttach==alreadyAttached ) return 1; /* Already open. */
    db_close_config();
  }
  zDbName = db_configdb_name(isOptional);
  if( zDbName==0 ) return 0;
  if( file_size(zDbName, ExtFILE)<1024*3 ){
    char *zHome = file_dirname(zDbName);
    int rc;
    if( file_isdir(zHome, ExtFILE)==0 ){
      file_mkdir(zHome, ExtFILE, 0);
    }
    rc = file_access(zHome, W_OK);
    fossil_free(zHome);
    if( rc ){
      if( isOptional ) return 0;
      fossil_panic("home directory \"%s\" must be writeable", zHome);
    }
    db_init_database(zDbName, zConfigSchema, (char*)0);
  }
  if( file_access(zDbName, W_OK) ){
    if( isOptional ) return 0;
    fossil_panic("configuration file %s must be writeable", zDbName);
  }
1626
1627
1628
1629
1630
1631
1632

1633

1634
1635
1636
1637
1638
1639
1640
const char *db_repository_filename(void){
  static char *zRepo = 0;
  assert( g.localOpen );
  assert( g.zLocalRoot );
  if( zRepo==0 ){
    zRepo = db_lget("repository", 0);
    if( zRepo && !file_is_absolute_path(zRepo) ){

      zRepo = mprintf("%s%s", g.zLocalRoot, zRepo);

    }
  }
  return zRepo;
}

/*
** Returns non-zero if the default value for the "allow-symlinks" setting







>

>







1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
const char *db_repository_filename(void){
  static char *zRepo = 0;
  assert( g.localOpen );
  assert( g.zLocalRoot );
  if( zRepo==0 ){
    zRepo = db_lget("repository", 0);
    if( zRepo && !file_is_absolute_path(zRepo) ){
      char * zFree = zRepo;
      zRepo = mprintf("%s%s", g.zLocalRoot, zRepo);
      fossil_free(zFree);
    }
  }
  return zRepo;
}

/*
** Returns non-zero if the default value for the "allow-symlinks" setting
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
      db_multi_exec("ALTER TABLE vfile ADD COLUMN mhash;");
      db_multi_exec(
        "UPDATE vfile"
        "   SET mhash=(SELECT uuid FROM blob WHERE blob.rid=vfile.mrid)"
        " WHERE mrid!=rid;"
      );
      if( !db_table_has_column("localdb", "vmerge", "mhash") ){
        db_multi_exec("ALTER TABLE vmerge RENAME TO old_vmerge;");
        db_multi_exec(zLocalSchemaVmerge /*works-like:""*/);
        db_multi_exec(  
           "INSERT OR IGNORE INTO vmerge(id,merge,mhash)"
           "  SELECT id, merge, blob.uuid FROM old_vmerge, blob"
           "   WHERE old_vmerge.merge=blob.rid;"
           "DROP TABLE old_vmerge;"
        );
      }
    }







|
|
|







1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
      db_multi_exec("ALTER TABLE vfile ADD COLUMN mhash;");
      db_multi_exec(
        "UPDATE vfile"
        "   SET mhash=(SELECT uuid FROM blob WHERE blob.rid=vfile.mrid)"
        " WHERE mrid!=rid;"
      );
      if( !db_table_has_column("localdb", "vmerge", "mhash") ){
        db_exec_sql("ALTER TABLE vmerge RENAME TO old_vmerge;");
        db_exec_sql(zLocalSchemaVmerge);
        db_exec_sql(  
           "INSERT OR IGNORE INTO vmerge(id,merge,mhash)"
           "  SELECT id, merge, blob.uuid FROM old_vmerge, blob"
           "   WHERE old_vmerge.merge=blob.rid;"
           "DROP TABLE old_vmerge;"
        );
      }
    }
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
  if( !setupUserOnly ){
    db_multi_exec(
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('nobody','','gjorz','Nobody');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('developer','','dei','Dev');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('reader','','kptw','Reader');"
    );
  }
}

/*







|







2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
  if( !setupUserOnly ){
    db_multi_exec(
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('nobody','','gjorz','Nobody');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('developer','','ei','Dev');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('reader','','kptw','Reader');"
    );
  }
}

/*
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318

2319








2320
2321
2322
2323
2324
2325
2326
2327
2328
2329

/*
** SQL functions for debugging.
**
** The print() function writes its arguments on stdout, but only
** if the -sqlprint command-line option is turned on.
*/
LOCAL void db_sql_print(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int i;
  if( g.fSqlPrint ){
    for(i=0; i<argc; i++){
      char c = i==argc-1 ? '\n' : ' ';
      fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
    }
  }
}
LOCAL int db_sql_trace(unsigned m, void *notUsed, void *pP, void *pX){
  sqlite3_stmt *pStmt = (sqlite3_stmt*)pP;
  char *zSql;
  int n;
  const char *zArg = (const char*)pX;

  if( zArg[0]=='-' ) return 0;








  zSql = sqlite3_expanded_sql(pStmt);
  n = (int)strlen(zSql);
  fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
  sqlite3_free(zSql);
  return 0;
}

/*
** Implement the user() SQL function.  user() takes no arguments and
** returns the user ID of the current user.







|

















>

>
>
>
>
>
>
>
>


|







2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410

/*
** SQL functions for debugging.
**
** The print() function writes its arguments on stdout, but only
** if the -sqlprint command-line option is turned on.
*/
void db_sql_print(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int i;
  if( g.fSqlPrint ){
    for(i=0; i<argc; i++){
      char c = i==argc-1 ? '\n' : ' ';
      fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
    }
  }
}
LOCAL int db_sql_trace(unsigned m, void *notUsed, void *pP, void *pX){
  sqlite3_stmt *pStmt = (sqlite3_stmt*)pP;
  char *zSql;
  int n;
  const char *zArg = (const char*)pX;
  char zEnd[40];
  if( zArg[0]=='-' ) return 0;
  if( m & SQLITE_TRACE_PROFILE ){
    sqlite3_int64 nNano = *(sqlite3_int64*)pX;
    double rMillisec = 0.000001 * nNano;
    sqlite3_snprintf(sizeof(zEnd),zEnd," /* %.3fms */\n", rMillisec);
  }else{
    zEnd[0] = '\n';
    zEnd[1] = 0;
  }
  zSql = sqlite3_expanded_sql(pStmt);
  n = (int)strlen(zSql);
  fossil_trace("%s%s%s", zSql, (n>0 && zSql[n-1]==';') ? "" : ";", zEnd);
  sqlite3_free(zSql);
  return 0;
}

/*
** Implement the user() SQL function.  user() takes no arguments and
** returns the user ID of the current user.
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
    if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
  }
  return 0;
}

/*
** Swap the g.db and g.dbConfig connections so that the various db_* routines
** work on the ~/.fossil database instead of on the repository database.
** Be sure to swap them back after doing the operation.
**
** If the ~/.fossil database has already been opened as the main database or
** is attached to the main database, no connection swaps are required so this
** routine is a no-op.
*/
void db_swap_connections(void){
  /*
  ** When swapping the main database connection with the config database
  ** connection, the config database connection must be open (not simply
  ** attached); otherwise, the swap would end up leaving the main database
  ** connection invalid, defeating the very purpose of this routine.  This







|


|
|
|







2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
    if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
  }
  return 0;
}

/*
** Swap the g.db and g.dbConfig connections so that the various db_* routines
** work on the configuration database instead of on the repository database.
** Be sure to swap them back after doing the operation.
**
** If the configuration database has already been opened as the main database
** or is attached to the main database, no connection swaps are required so
** this routine is a no-op.
*/
void db_swap_connections(void){
  /*
  ** When swapping the main database connection with the config database
  ** connection, the config database connection must be open (not simply
  ** attached); otherwise, the swap would end up leaving the main database
  ** connection invalid, defeating the very purpose of this routine.  This
2631
2632
2633
2634
2635
2636
2637

2638



2639
2640
2641
2642
2643
2644
2645
    db_swap_connections();
    z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
    db_swap_connections();
  }
  if( pSetting!=0 && pSetting->versionable ){
    /* This is a versionable setting, try and get the info from a
    ** checked out file */

    z = db_get_versioned(zName, z);



  }
  if( z==0 ){
    if( zDefault==0 && pSetting && pSetting->def[0] ){
      z = fossil_strdup(pSetting->def);
    }else{
      z = fossil_strdup(zDefault);
    }







>

>
>
>







2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
    db_swap_connections();
    z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
    db_swap_connections();
  }
  if( pSetting!=0 && pSetting->versionable ){
    /* This is a versionable setting, try and get the info from a
    ** checked out file */
    char * zZ = z;
    z = db_get_versioned(zName, z);
    if(zZ != z){
      fossil_free(zZ);
    }
  }
  if( z==0 ){
    if( zDefault==0 && pSetting && pSetting->def[0] ){
      z = fossil_strdup(pSetting->def);
    }else{
      z = fossil_strdup(zDefault);
    }
3076
3077
3078
3079
3080
3081
3082
3083
3084



3085
3086
3087
3088
3089
3090
3091
3092


3093
3094
3095
3096
3097
3098
3099
/*
** Define all settings, which can be controlled via the set/unset
** command.
**
** var is the name of the internal configuration name for db_(un)set.
** If var is 0, the settings name is used.
**
** width is the length for the edit field on the behavior page, 0
** is used for on/off checkboxes.



**
** The behaviour page doesn't use a special layout. It lists all
** set-commands and displays the 'set'-help as info.
*/
struct Setting {
  const char *name;     /* Name of the setting */
  const char *var;      /* Internal variable name used by db_set() */
  int width;            /* Width of display.  0 for boolean values. */


  int versionable;      /* Is this setting versionable? */
  int forceTextArea;    /* Force using a text area for display? */
  const char *def;      /* Default value */
};
#endif /* INTERFACE */

/*







|
|
>
>
>







|
>
>







3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
/*
** Define all settings, which can be controlled via the set/unset
** command.
**
** var is the name of the internal configuration name for db_(un)set.
** If var is 0, the settings name is used.
**
** width is the length for the edit field on the behavior page, 0 is
** used for on/off checkboxes. A negative value indicates that that
** page should not render this setting. Such values may be rendered
** separately/manually on another page, e.g., /setup_access, and are
** exposed via the CLI settings command.
**
** The behaviour page doesn't use a special layout. It lists all
** set-commands and displays the 'set'-help as info.
*/
struct Setting {
  const char *name;     /* Name of the setting */
  const char *var;      /* Internal variable name used by db_set() */
  int width;            /* Width of display.  0 for boolean values and
                        ** negative for values which should not appear
                        ** on the /setup_settings page. */
  int versionable;      /* Is this setting versionable? */
  int forceTextArea;    /* Force using a text area for display? */
  const char *def;      /* Default value */
};
#endif /* INTERFACE */

/*
3436
3437
3438
3439
3440
3441
3442







3443
3444
3445
3446
3447
3448
3449
** when running as a web-server, Fossil does not open the
** global configuration database.
*/
/*
** SETTING: max-upload       width=25 default=250000
** A limit on the size of uplink HTTP requests.
*/







/*
** SETTING: mtime-changes    boolean default=on
** Use file modification times (mtimes) to detect when
** files have been modified.  If disabled, all managed files
** are hashed to detect changes, which can be slow for large
** projects.
*/







>
>
>
>
>
>
>







3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
** when running as a web-server, Fossil does not open the
** global configuration database.
*/
/*
** SETTING: max-upload       width=25 default=250000
** A limit on the size of uplink HTTP requests.
*/
/*
** SETTING: mimetypes        width=40 versionable block-text
** A list of file extension-to-mimetype mappings, one per line. e.g.
** "foo application/x-foo". File extensions are compared
** case-insensitively in the order listed in this setting.  A leading
** '.' on file extensions is permitted but not required.
*/
/*
** SETTING: mtime-changes    boolean default=on
** Use file modification times (mtimes) to detect when
** files have been modified.  If disabled, all managed files
** are hashed to detect changes, which can be slow for large
** projects.
*/
3464
3465
3466
3467
3468
3469
3470







3471
3472
3473
3474
3475
3476
3477
/*
** SETTING: proxy            width=32 default=off
** URL of the HTTP proxy.  If undefined or "off" then
** the "http_proxy" environment variable is consulted.
** If the http_proxy environment variable is undefined
** then a direct HTTP connection is used.
*/







/*
** SETTING: relative-paths   boolean default=on
** When showing changes and extras, report paths relative
** to the current working directory.
*/
/*
** SETTING: repo-cksum       boolean default=on







>
>
>
>
>
>
>







3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
/*
** SETTING: proxy            width=32 default=off
** URL of the HTTP proxy.  If undefined or "off" then
** the "http_proxy" environment variable is consulted.
** If the http_proxy environment variable is undefined
** then a direct HTTP connection is used.
*/
/*
** SETTING: redirect-to-https   default=0 width=-1
** Specifies whether or not to redirect http:// requests to
** https:// URIs. A value of 0 (the default) means not to
** redirect, 1 means to redirect only the /login page, and 2
** means to always redirect.
*/
/*
** SETTING: relative-paths   boolean default=on
** When showing changes and extras, report paths relative
** to the current working directory.
*/
/*
** SETTING: repo-cksum       boolean default=on
3584
3585
3586
3587
3588
3589
3590




















3591
3592
3593
3594
3595
3596
3597
*/
/*
** SETTING: th1-uri-regexp   width=40 block-text
** Specify which URI's are allowed in HTTP requests from
** TH1 scripts.  If empty, no HTTP requests are allowed
** whatsoever.
*/




















/*
** SETTING: uv-sync          boolean default=off
** If true, automatically send unversioned files as part
** of a "fossil clone" or "fossil sync" command.  The
** default is false, in which case the -u option is
** needed to clone or sync unversioned files.
*/







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







3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
*/
/*
** SETTING: th1-uri-regexp   width=40 block-text
** Specify which URI's are allowed in HTTP requests from
** TH1 scripts.  If empty, no HTTP requests are allowed
** whatsoever.
*/
/*
** SETTING: default-csp      width=40 block-text
**
** The text of the Content Security Policy that is included
** in the Content-Security-Policy: header field of the HTTP
** reply and in the default HTML <head> section that is added when the
** skin header does not specify a <head> section.  The text "$nonce"
** is replaced by the random nonce that is created for each web page.
**
** If this setting is an empty string or is omitted, then
** the following default Content Security Policy is used:
**
**     default-src 'self' data:;
**     script-src 'self' 'nonce-$nonce';
**     style-src 'self' 'unsafe-inline';
**
** The default CSP is recommended.  The main reason to change
** this setting would be to add CDNs from which it is safe to
** load additional content.
*/
/*
** SETTING: uv-sync          boolean default=off
** If true, automatically send unversioned files as part
** of a "fossil clone" or "fossil sync" command.  The
** default is false, in which case the -u option is
** needed to clone or sync unversioned files.
*/
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
** file exists.
**
** The "unset" command clears a setting.
**
** Settings can have both a "local" repository-only value and "global" value
** that applies to all repositories.  The local values are stored in the
** "config" table of the repository and the global values are stored in the
** $HOME/.fossil file on unix or in the %LOCALAPPDATA%/_fossil file on Windows.
** If both a local and a global value exists for a setting, the local value
** takes precedence.  This command normally operates on the local settings.
** Use the --global option to change global settings.
**
** Options:
**   --global   set or unset the given property globally instead of
**              setting or unsetting it for the open repository only.
**
**   --exact    only consider exact name matches.
**







<
|
|
|







3776
3777
3778
3779
3780
3781
3782

3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
** file exists.
**
** The "unset" command clears a setting.
**
** Settings can have both a "local" repository-only value and "global" value
** that applies to all repositories.  The local values are stored in the
** "config" table of the repository and the global values are stored in the

** configuration database.  If both a local and a global value exists for a
** setting, the local value takes precedence.  This command normally operates
** on the local settings.  Use the --global option to change global settings.
**
** Options:
**   --global   set or unset the given property globally instead of
**              setting or unsetting it for the open repository only.
**
**   --exact    only consider exact name matches.
**
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805

/*
** COMMAND: test-without-rowid
**
** Usage: %fossil test-without-rowid FILENAME...
**
** Change the Fossil repository FILENAME to make use of the WITHOUT ROWID
** optimization.  FILENAME can also be the ~/.fossil file or a local
** .fslckout or _FOSSIL_ file.
**
** The purpose of this command is for testing the WITHOUT ROWID capabilities
** of SQLite.  There is no big advantage to using WITHOUT ROWID in Fossil.
**
** Options:
**    --dryrun | -n         No changes.  Just print what would happen.
*/







|
|







3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928

/*
** COMMAND: test-without-rowid
**
** Usage: %fossil test-without-rowid FILENAME...
**
** Change the Fossil repository FILENAME to make use of the WITHOUT ROWID
** optimization.  FILENAME can also be the configuration database file
** (~/.fossil or ~/.config/fossil.db) or a local .fslckout or _FOSSIL_ file.
**
** The purpose of this command is for testing the WITHOUT ROWID capabilities
** of SQLite.  There is no big advantage to using WITHOUT ROWID in Fossil.
**
** Options:
**    --dryrun | -n         No changes.  Just print what would happen.
*/
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000


4001
4002
4003
4004
4005
4006
4007
  int rcvid = 0;
  db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
  if( g.argc==3 ){
    rcvid = atoi(g.argv[2]);
  }else if( g.argc!=2 ){
    fossil_fatal("wrong number of arguments");
  } 
  fossil_print("legecy:              %z\n", db_fingerprint(rcvid, 0));
  fossil_print("version-1:           %z\n", db_fingerprint(rcvid, 1));
  if( g.localOpen ){
    fossil_print("localdb:             %z\n", db_lget("fingerprint","(none)"));
    fossil_print("db_fingerprint_ok(): %d\n", db_fingerprint_ok());
  }


}

/*
** Set the value of the "checkout" entry in the VVAR table.
**
** Also set "fingerprint" and "checkout-hash".
*/







|





>
>







4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
  int rcvid = 0;
  db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
  if( g.argc==3 ){
    rcvid = atoi(g.argv[2]);
  }else if( g.argc!=2 ){
    fossil_fatal("wrong number of arguments");
  } 
  fossil_print("legacy:              %z\n", db_fingerprint(rcvid, 0));
  fossil_print("version-1:           %z\n", db_fingerprint(rcvid, 1));
  if( g.localOpen ){
    fossil_print("localdb:             %z\n", db_lget("fingerprint","(none)"));
    fossil_print("db_fingerprint_ok(): %d\n", db_fingerprint_ok());
  }
  fossil_print("Fossil version:      %s - %.10s %.19s\n", 
    RELEASE_VERSION, MANIFEST_DATE, MANIFEST_UUID);
}

/*
** Set the value of the "checkout" entry in the VVAR table.
**
** Also set "fingerprint" and "checkout-hash".
*/
Changes to src/default_css.txt.
453
454
455
456
457
458
459






460
461
462
463
464
465
466
td.tktDspLabel {
  text-align: right;
}
td.tktDspValue {
  text-align: left;
  vertical-align: top;
  background-color: #d0d0d0;






}
span.tktError {
  color: red;
  font-weight: bold;
}
table.rpteditex {
  float: right;







>
>
>
>
>
>







453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
td.tktDspLabel {
  text-align: right;
}
td.tktDspValue {
  text-align: left;
  vertical-align: top;
  background-color: #d0d0d0;
}
td.tktTlOpen {
  color: #800;
}
td.tktTlClosed {
  color: #888;
}
span.tktError {
  color: red;
  font-weight: bold;
}
table.rpteditex {
  float: right;
733
734
735
736
737
738
739













740
741
742
743
744




745
746
747
748
749
750
751
  border: 2px solid #ff0;
}
div.forumEdit {
  border: 1px solid black;
  padding-left: 1ex;
  padding-right: 1ex;
}













div.forumHier, div.forumTime {
  border: 1px solid black;
  padding-left: 1ex;
  padding-right: 1ex;
  margin-top: 1ex;




}
div.forumSel {
  background-color: #cef;
}
div.forumObs {
  color: #bbb;
}







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





>
>
>
>







739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  border: 2px solid #ff0;
}
div.forumEdit {
  border: 1px solid black;
  padding-left: 1ex;
  padding-right: 1ex;
}
div.forumTimeline {
  border: 1px solid black;
  padding-left: 1ex;
  padding-right: 1ex;
  max-width: 50em;
  overflow: auto;
}
div.forumTimeline code {
  white-space: pre-wrap;
}
div.markdown code {
  white-space: pre-wrap;
}
div.forumHier, div.forumTime {
  border: 1px solid black;
  padding-left: 1ex;
  padding-right: 1ex;
  margin-top: 1ex;
}
div.forumPostBody {
  max-height: 40em;
  overflow: auto;
}
div.forumSel {
  background-color: #cef;
}
div.forumObs {
  color: #bbb;
}
791
792
793
794
795
796
797

























//Note: .16em is suitable for element grouping.
  margin-left: .16em;
  margin-right: 0;
}
.nobr {
  white-space: nowrap;
}
































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
//Note: .16em is suitable for element grouping.
  margin-left: .16em;
  margin-right: 0;
}
.nobr {
  white-space: nowrap;
}
.accordion {
  cursor: pointer;
}
.accordion_btn {
  display: inline-block;
  width: 16px;
  height: 16px;
  margin-right: .5em;
  vertical-align: middle;
}
// Note: the order of the next 3 entries should be
// maintained for the hierarchical cascade to work.
.accordion > .accordion_btn_plus {
  display: none;
}
.accordion_closed > .accordion_btn_minus {
  display: none;
}
.accordion_closed > .accordion_btn_plus {
  display: inline-block;
}
.accordion_panel {
  overflow: hidden;
  transition: max-height 0.25s ease-out;
}
Changes to src/diff.c.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#define DIFF_TOO_MANY_CHANGES \
    "more than 10,000 changes\n"

#define DIFF_WHITESPACE_ONLY \
    "whitespace changes only\n"

/*
** Maximum length of a line in a text file, in bytes.  (2**13 = 8192 bytes)
*/
#define LENGTH_MASK_SZ  13
#define LENGTH_MASK     ((1<<LENGTH_MASK_SZ)-1)

#endif /* INTERFACE */

/*
** Information about each line of a file being diffed.
**
** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
** of the line.  If any line is longer than LENGTH_MASK characters,
** the file is considered binary.
*/
typedef struct DLine DLine;
struct DLine {
  const char *z;        /* The text of the line */
  unsigned int h;       /* Hash of the line */
  unsigned short indent;  /* Indent of the line. Only !=0 with -w/-Z option */
  unsigned short n;     /* number of bytes */
  unsigned int iNext;   /* 1+(Index of next line with same the same hash) */

  /* an array of DLine elements serves two purposes.  The fields
  ** above are one per line of input text.  But each entry is also
  ** a bucket in a hash table, as follows: */
  unsigned int iHash;   /* 1+(first entry in the hash chain) */
};

/*
** Length of a dline
*/
#define LENGTH(X)   ((X)->n)








|

|













|
|

|
|




|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#define DIFF_TOO_MANY_CHANGES \
    "more than 10,000 changes\n"

#define DIFF_WHITESPACE_ONLY \
    "whitespace changes only\n"

/*
** Maximum length of a line in a text file, in bytes.  (2**15 = 32768 bytes)
*/
#define LENGTH_MASK_SZ  15
#define LENGTH_MASK     ((1<<LENGTH_MASK_SZ)-1)

#endif /* INTERFACE */

/*
** Information about each line of a file being diffed.
**
** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
** of the line.  If any line is longer than LENGTH_MASK characters,
** the file is considered binary.
*/
typedef struct DLine DLine;
struct DLine {
  const char *z;          /* The text of the line */
  u64 h;                  /* Hash of the line */
  unsigned short indent;  /* Indent of the line. Only !=0 with -w/-Z option */
  unsigned short n;       /* number of bytes */
  unsigned int iNext;     /* 1+(Index of next line with same the same hash) */

  /* an array of DLine elements serves two purposes.  The fields
  ** above are one per line of input text.  But each entry is also
  ** a bucket in a hash table, as follows: */
  unsigned int iHash;     /* 1+(first entry in the hash chain) */
};

/*
** Length of a dline
*/
#define LENGTH(X)   ((X)->n)

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  int *aEdit;        /* Array of copy/delete/insert triples */
  int nEdit;         /* Number of integers (3x num of triples) in aEdit[] */
  int nEditAlloc;    /* Space allocated for aEdit[] */
  DLine *aFrom;      /* File on left side of the diff */
  int nFrom;         /* Number of lines in aFrom[] */
  DLine *aTo;        /* File on right side of the diff */
  int nTo;           /* Number of lines in aTo[] */
  int (*same_fn)(const DLine*,const DLine*); /* comparison function */
};

/*
** Count the number of lines in the input string.  Include the last line
** in the count even if it lacks the \n terminator.  If an empty string
** is specified, the number of lines is zero.  For the purposes of this
** function, a string is considered empty if it contains no characters







|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  int *aEdit;        /* Array of copy/delete/insert triples */
  int nEdit;         /* Number of integers (3x num of triples) in aEdit[] */
  int nEditAlloc;    /* Space allocated for aEdit[] */
  DLine *aFrom;      /* File on left side of the diff */
  int nFrom;         /* Number of lines in aFrom[] */
  DLine *aTo;        /* File on right side of the diff */
  int nTo;           /* Number of lines in aTo[] */
  int (*xDiffer)(const DLine*,const DLine*); /* comparison function */
};

/*
** Count the number of lines in the input string.  Include the last line
** in the count even if it lacks the \n terminator.  If an empty string
** is specified, the number of lines is zero.  For the purposes of this
** function, a string is considered empty if it contains no characters
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
static DLine *break_into_lines(
  const char *z,
  int n,
  int *pnLine,
  u64 diffFlags
){
  int nLine, i, k, nn, s, x;
  unsigned int h, h2;
  DLine *a;
  const char *zNL;

  if( count_lines(z, n, &nLine)==0 ){
    return 0;
  }
  assert( nLine>0 || z[0]=='\0' );







|







162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
static DLine *break_into_lines(
  const char *z,
  int n,
  int *pnLine,
  u64 diffFlags
){
  int nLine, i, k, nn, s, x;
  u64 h, h2;
  DLine *a;
  const char *zNL;

  if( count_lines(z, n, &nLine)==0 ){
    return 0;
  }
  assert( nLine>0 || z[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
      int numws = 0;
      while( s<k && fossil_isspace(z[s]) ){ s++; }
      for(h=0, x=s; x<k; x++){
        char c = z[x];
        if( fossil_isspace(c) ){
          ++numws;
        }else{
          h += c;
          h *= 0x9e3779b1;
        }
      }
      k -= numws;
    }else{


      for(h=0, x=s; x<k; x++){
        h += z[x];
        h *= 0x9e3779b1;

      }



    }
    a[i].indent = s;
    a[i].h = h = (h<<LENGTH_MASK_SZ) | (k-s);
    h2 = h % nLine;
    a[i].iNext = a[h2].iHash;
    a[h2].iHash = i+1;
    z += nn+1; n -= nn+1;
    i++;
  }while( zNL[0]!='\0' && zNL[1]!='\0' );
  assert( i==nLine );

  /* Return results */
  *pnLine = nLine;
  return a;
}

/*
** Return true if two DLine elements are identical.
*/
static int same_dline(const DLine *pA, const DLine *pB){

  return pA->h==pB->h && memcmp(pA->z,pB->z, pA->h&LENGTH_MASK)==0;
}

/*
** Return true if two DLine elements are identical, ignoring
** all whitespace. The indent field of pA/pB already points
** to the first non-space character in the string.
*/

static int same_dline_ignore_allws(const DLine *pA, const DLine *pB){
  int a = pA->indent, b = pB->indent;
  if( pA->h==pB->h ){
    while( a<pA->n || b<pB->n ){
      if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 0;
      while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
      while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
    }
    return pA->n-a == pB->n-b;
  }
  return 0;
}

/*
** Return true if the regular expression *pRe matches any of the
** N dlines
*/
static int re_dline_match(







|
<




>
>
|
|
<
>

>
>
>


|














|


>
|



|








|



|

|







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
      int numws = 0;
      while( s<k && fossil_isspace(z[s]) ){ s++; }
      for(h=0, x=s; x<k; x++){
        char c = z[x];
        if( fossil_isspace(c) ){
          ++numws;
        }else{
          h = (h^c)*9000000000000000041LL;

        }
      }
      k -= numws;
    }else{
      int k2 = k & ~0x7;
      u64 m;
      for(h=0, x=s; x<k2; x += 8){
        memcpy(&m, z+x, 8);

        h = (h^m)*9000000000000000041LL;
      }
      m = 0;
      memcpy(&m, z+x, k-k2);
      h ^= m;
    }
    a[i].indent = s;
    a[i].h = h = ((h%281474976710597LL)<<LENGTH_MASK_SZ) | (k-s);
    h2 = h % nLine;
    a[i].iNext = a[h2].iHash;
    a[h2].iHash = i+1;
    z += nn+1; n -= nn+1;
    i++;
  }while( zNL[0]!='\0' && zNL[1]!='\0' );
  assert( i==nLine );

  /* Return results */
  *pnLine = nLine;
  return a;
}

/*
** Return zero if two DLine elements are identical.
*/
static int same_dline(const DLine *pA, const DLine *pB){
  if( pA->h!=pB->h ) return 1;
  return memcmp(pA->z,pB->z, pA->h&LENGTH_MASK);
}

/*
** Return zero if two DLine elements are identical, ignoring
** all whitespace. The indent field of pA/pB already points
** to the first non-space character in the string.
*/

static int same_dline_ignore_allws(const DLine *pA, const DLine *pB){
  int a = pA->indent, b = pB->indent;
  if( pA->h==pB->h ){
    while( a<pA->n || b<pB->n ){
      if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 1;
      while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
      while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
    }
    return pA->n-a != pB->n-b;
  }
  return 1;
}

/*
** Return true if the regular expression *pRe matches any of the
** N dlines
*/
static int re_dline_match(
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
  int i, j;                  /* Loop counters */
  int k;                     /* Length of a candidate subsequence */
  int iSXb = iS1;            /* Best match so far */
  int iSYb = iS2;            /* Best match so far */

  for(i=iS1; i<iE1-mxLength; i++){
    for(j=iS2; j<iE2-mxLength; j++){
      if( !p->same_fn(&p->aFrom[i], &p->aTo[j]) ) continue;
      if( mxLength && !p->same_fn(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
        continue;
      }
      k = 1;
      while( i+k<iE1 && j+k<iE2 && p->same_fn(&p->aFrom[i+k],&p->aTo[j+k]) ){
        k++;
      }
      if( k>mxLength ){
        iSXb = i;
        iSYb = j;
        mxLength = k;
      }







|
|



|







1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
  int i, j;                  /* Loop counters */
  int k;                     /* Length of a candidate subsequence */
  int iSXb = iS1;            /* Best match so far */
  int iSYb = iS2;            /* Best match so far */

  for(i=iS1; i<iE1-mxLength; i++){
    for(j=iS2; j<iE2-mxLength; j++){
      if( p->xDiffer(&p->aFrom[i], &p->aTo[j]) ) continue;
      if( mxLength && p->xDiffer(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
        continue;
      }
      k = 1;
      while( i+k<iE1 && j+k<iE2 && p->xDiffer(&p->aFrom[i+k],&p->aTo[j+k])==0 ){
        k++;
      }
      if( k>mxLength ){
        iSXb = i;
        iSYb = j;
        mxLength = k;
      }
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
  iSYb = iSYp = iS2;
  iEYb = iEYp = iS2;
  mid = (iE1 + iS1)/2;
  for(i=iS1; i<iE1; i++){
    int limit = 0;
    j = p->aTo[p->aFrom[i].h % p->nTo].iHash;
    while( j>0
      && (j-1<iS2 || j>=iE2 || !p->same_fn(&p->aFrom[i], &p->aTo[j-1]))
    ){
      if( limit++ > 10 ){
        j = 0;
        break;
      }
      j = p->aTo[j-1].iNext;
    }
    if( j==0 ) continue;
    assert( i>=iSXb && i>=iSXp );
    if( i<iEXb && j>=iSYb && j<iEYb ) continue;
    if( i<iEXp && j>=iSYp && j<iEYp ) continue;
    iSX = i;
    iSY = j-1;
    pA = &p->aFrom[iSX-1];
    pB = &p->aTo[iSY-1];
    n = minInt(iSX-iS1, iSY-iS2);
    for(k=0; k<n && p->same_fn(pA,pB); k++, pA--, pB--){}
    iSX -= k;
    iSY -= k;
    iEX = i+1;
    iEY = j;
    pA = &p->aFrom[iEX];
    pB = &p->aTo[iEY];
    n = minInt(iE1-iEX, iE2-iEY);
    for(k=0; k<n && p->same_fn(pA,pB); k++, pA++, pB++){}
    iEX += k;
    iEY += k;
    skew = (iSX-iS1) - (iSY-iS2);
    if( skew<0 ) skew = -skew;
    dist = (iSX+iEX)/2 - mid;
    if( dist<0 ) dist = -dist;
    score = (iEX - iSX)*(sqlite3_int64)span - (skew + dist);







|
















|







|







1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
  iSYb = iSYp = iS2;
  iEYb = iEYp = iS2;
  mid = (iE1 + iS1)/2;
  for(i=iS1; i<iE1; i++){
    int limit = 0;
    j = p->aTo[p->aFrom[i].h % p->nTo].iHash;
    while( j>0
      && (j-1<iS2 || j>=iE2 || p->xDiffer(&p->aFrom[i], &p->aTo[j-1]))
    ){
      if( limit++ > 10 ){
        j = 0;
        break;
      }
      j = p->aTo[j-1].iNext;
    }
    if( j==0 ) continue;
    assert( i>=iSXb && i>=iSXp );
    if( i<iEXb && j>=iSYb && j<iEYb ) continue;
    if( i<iEXp && j>=iSYp && j<iEYp ) continue;
    iSX = i;
    iSY = j-1;
    pA = &p->aFrom[iSX-1];
    pB = &p->aTo[iSY-1];
    n = minInt(iSX-iS1, iSY-iS2);
    for(k=0; k<n && p->xDiffer(pA,pB)==0; k++, pA--, pB--){}
    iSX -= k;
    iSY -= k;
    iEX = i+1;
    iEY = j;
    pA = &p->aFrom[iEX];
    pB = &p->aTo[iEY];
    n = minInt(iE1-iEX, iE2-iEY);
    for(k=0; k<n && p->xDiffer(pA,pB)==0; k++, pA++, pB++){}
    iEX += k;
    iEY += k;
    skew = (iSX-iS1) - (iSY-iS2);
    if( skew<0 ) skew = -skew;
    dist = (iSX+iEX)/2 - mid;
    if( dist<0 ) dist = -dist;
    score = (iEX - iSX)*(sqlite3_int64)span - (skew + dist);
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
*/
static void diff_all(DContext *p){
  int mnE, iS, iE1, iE2;

  /* Carve off the common header and footer */
  iE1 = p->nFrom;
  iE2 = p->nTo;
  while( iE1>0 && iE2>0 && p->same_fn(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
    iE1--;
    iE2--;
  }
  mnE = iE1<iE2 ? iE1 : iE2;
  for(iS=0; iS<mnE && p->same_fn(&p->aFrom[iS],&p->aTo[iS]); iS++){}

  /* do the difference */
  if( iS>0 ){
    appendTriple(p, iS, 0, 0);
  }
  diff_step(p, iS, iE1, iS, iE2);
  if( iE1<p->nFrom ){







|




|







1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
*/
static void diff_all(DContext *p){
  int mnE, iS, iE1, iE2;

  /* Carve off the common header and footer */
  iE1 = p->nFrom;
  iE2 = p->nTo;
  while( iE1>0 && iE2>0 && p->xDiffer(&p->aFrom[iE1-1], &p->aTo[iE2-1])==0 ){
    iE1--;
    iE2--;
  }
  mnE = iE1<iE2 ? iE1 : iE2;
  for(iS=0; iS<mnE && p->xDiffer(&p->aFrom[iS],&p->aTo[iS])==0; iS++){}

  /* do the difference */
  if( iS>0 ){
    appendTriple(p, iS, 0, 0);
  }
  diff_step(p, iS, iE1, iS, iE2);
  if( iE1<p->nFrom ){
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
    lnFrom += cpy;
    lnTo += cpy;

    /* Shift insertions toward the beginning of the file */
    while( cpy>0 && del==0 && ins>0 ){
      DLine *pTop = &p->aFrom[lnFrom-1];  /* Line before start of insert */
      DLine *pBtm = &p->aTo[lnTo+ins-1];  /* Last line inserted */
      if( p->same_fn(pTop, pBtm)==0 ) break;
      if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
      lnFrom--;
      lnTo--;
      p->aEdit[r]--;
      p->aEdit[r+3]++;
      cpy--;
    }

    /* Shift insertions toward the end of the file */
    while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
      DLine *pTop = &p->aTo[lnTo];       /* First line inserted */
      DLine *pBtm = &p->aTo[lnTo+ins];   /* First line past end of insert */
      if( p->same_fn(pTop, pBtm)==0 ) break;
      if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
      lnFrom++;
      lnTo++;
      p->aEdit[r]++;
      p->aEdit[r+3]--;
      cpy++;
    }

    /* Shift deletions toward the beginning of the file */
    while( cpy>0 && del>0 && ins==0 ){
      DLine *pTop = &p->aFrom[lnFrom-1];     /* Line before start of delete */
      DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
      if( p->same_fn(pTop, pBtm)==0 ) break;
      if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
      lnFrom--;
      lnTo--;
      p->aEdit[r]--;
      p->aEdit[r+3]++;
      cpy--;
    }

    /* Shift deletions toward the end of the file */
    while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
      DLine *pTop = &p->aFrom[lnFrom];     /* First line deleted */
      DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
      if( p->same_fn(pTop, pBtm)==0 ) break;
      if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
      lnFrom++;
      lnTo++;
      p->aEdit[r]++;
      p->aEdit[r+3]--;
      cpy++;
    }







|












|












|












|







1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
    lnFrom += cpy;
    lnTo += cpy;

    /* Shift insertions toward the beginning of the file */
    while( cpy>0 && del==0 && ins>0 ){
      DLine *pTop = &p->aFrom[lnFrom-1];  /* Line before start of insert */
      DLine *pBtm = &p->aTo[lnTo+ins-1];  /* Last line inserted */
      if( p->xDiffer(pTop, pBtm) ) break;
      if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
      lnFrom--;
      lnTo--;
      p->aEdit[r]--;
      p->aEdit[r+3]++;
      cpy--;
    }

    /* Shift insertions toward the end of the file */
    while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
      DLine *pTop = &p->aTo[lnTo];       /* First line inserted */
      DLine *pBtm = &p->aTo[lnTo+ins];   /* First line past end of insert */
      if( p->xDiffer(pTop, pBtm) ) break;
      if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
      lnFrom++;
      lnTo++;
      p->aEdit[r]++;
      p->aEdit[r+3]--;
      cpy++;
    }

    /* Shift deletions toward the beginning of the file */
    while( cpy>0 && del>0 && ins==0 ){
      DLine *pTop = &p->aFrom[lnFrom-1];     /* Line before start of delete */
      DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
      if( p->xDiffer(pTop, pBtm) ) break;
      if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
      lnFrom--;
      lnTo--;
      p->aEdit[r]--;
      p->aEdit[r+3]++;
      cpy--;
    }

    /* Shift deletions toward the end of the file */
    while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
      DLine *pTop = &p->aFrom[lnFrom];     /* First line deleted */
      DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
      if( p->xDiffer(pTop, pBtm) ) break;
      if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
      lnFrom++;
      lnTo++;
      p->aEdit[r]++;
      p->aEdit[r+3]--;
      cpy++;
    }
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
  ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0;
  blob_to_utf8_no_bom(pA_Blob, 0);
  blob_to_utf8_no_bom(pB_Blob, 0);

  /* Prepare the input files */
  memset(&c, 0, sizeof(c));
  if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
    c.same_fn = same_dline_ignore_allws;
  }else{
    c.same_fn = same_dline;
  }
  c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
                             &c.nFrom, diffFlags);
  c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
                           &c.nTo, diffFlags);
  if( c.aFrom==0 || c.aTo==0 ){
    fossil_free(c.aFrom);







|

|







1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
  ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0;
  blob_to_utf8_no_bom(pA_Blob, 0);
  blob_to_utf8_no_bom(pB_Blob, 0);

  /* Prepare the input files */
  memset(&c, 0, sizeof(c));
  if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
    c.xDiffer = same_dline_ignore_allws;
  }else{
    c.xDiffer = same_dline;
  }
  c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
                             &c.nFrom, diffFlags);
  c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
                           &c.nTo, diffFlags);
  if( c.aFrom==0 || c.aTo==0 ){
    fossil_free(c.aFrom);
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
** will release it when it is finished with it.
*/
static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
  int i;

  memset(p, 0, sizeof(*p));
  if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
    p->c.same_fn = same_dline_ignore_allws;
  }else{
    p->c.same_fn = same_dline;
  }
  p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
                              diffFlags);
  if( p->c.aTo==0 ){
    return 1;
  }
  p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );







|

|







2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
** will release it when it is finished with it.
*/
static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
  int i;

  memset(p, 0, sizeof(*p));
  if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
    p->c.xDiffer = same_dline_ignore_allws;
  }else{
    p->c.xDiffer = same_dline;
  }
  p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
                              diffFlags);
  if( p->c.aTo==0 ){
    return 1;
  }
  p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );
Changes to src/dispatch.c.
425
426
427
428
429
430
431


432

433




























434
435
436
437
438
439


440
441
442
443
444
445
446
/*
** WEBPAGE: test-all-help
**
** Show all help text on a single page.  Useful for proof-reading.
*/
void test_all_help_page(void){
  int i;


  style_header("All Help Text");

  for(i=0; i<MX_COMMAND; i++){




























    if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue;
    @ <h2>%s(aCommand[i].zName):</h2>
    @ <blockquote>
    help_to_html(aCommand[i].zHelp, cgi_output_blob());
    @ </blockquote>
  }


  style_footer();
}

static void multi_column_list(const char **azWord, int nWord){
  int i, j, len;
  int mxLen = 0;
  int nCol;







>
>

>

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

|
|

|

>
>







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
/*
** WEBPAGE: test-all-help
**
** Show all help text on a single page.  Useful for proof-reading.
*/
void test_all_help_page(void){
  int i;
  Blob buf;
  blob_init(&buf,0,0);
  style_header("All Help Text");
  @ <dl>
  for(i=0; i<MX_COMMAND; i++){
    const char *zDesc;
    unsigned int e = aCommand[i].eCmdFlags;
    if( e & CMDFLAG_1ST_TIER ){
      zDesc = "1st tier command";
    }else if( e & CMDFLAG_2ND_TIER ){
      zDesc = "2nd tier command";
    }else if( e & CMDFLAG_TEST ){
      zDesc = "test command";
    }else if( e & CMDFLAG_WEBPAGE ){
      if( e & CMDFLAG_RAWCONTENT ){
        zDesc = "raw-content web page";
      }else{
        zDesc = "web page";
      }
    }else{
      blob_reset(&buf);
      if( e & CMDFLAG_VERSIONABLE ){
        blob_appendf(&buf, "versionable ");
      }
      if( e & CMDFLAG_BLOCKTEXT ){
        blob_appendf(&buf, "block-text ");
      }
      if( e & CMDFLAG_BOOLEAN ){
        blob_appendf(&buf, "boolean ");
      }
      blob_appendf(&buf,"setting");
      zDesc = blob_str(&buf);
    }
    if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue;
    @ <dt><big><b>%s(aCommand[i].zName)</b></big> (%s(zDesc))</dt>
    @ <dd>
    help_to_html(aCommand[i].zHelp, cgi_output_blob());
    @ </dd>
  }
  @ </dl>
  blob_reset(&buf);
  style_footer();
}

static void multi_column_list(const char **azWord, int nWord){
  int i, j, len;
  int mxLen = 0;
  int nCol;
Changes to src/doc.c.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  int n;
  const unsigned char *x;

  /* A table of mimetypes based on file content prefixes
  */
  static const struct {
    const char *zPrefix;       /* The file prefix */
    int size;                  /* Length of the prefix */
    const char *zMimetype;     /* The corresponding mimetype */
  } aMime[] = {
    { "GIF87a",                  6, "image/gif"  },
    { "GIF89a",                  6, "image/gif"  },
    { "\211PNG\r\n\032\n",       8, "image/png"  },
    { "\377\332\377",            3, "image/jpeg" },
    { "\377\330\377",            3, "image/jpeg" },







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  int n;
  const unsigned char *x;

  /* A table of mimetypes based on file content prefixes
  */
  static const struct {
    const char *zPrefix;       /* The file prefix */
    const int size;            /* Length of the prefix */
    const char *zMimetype;     /* The corresponding mimetype */
  } aMime[] = {
    { "GIF87a",                  6, "image/gif"  },
    { "GIF89a",                  6, "image/gif"  },
    { "\211PNG\r\n\032\n",       8, "image/png"  },
    { "\377\332\377",            3, "image/jpeg" },
    { "\377\330\377",            3, "image/jpeg" },
267
268
269
270
271
272
273

274
275
276
277
278
279
280
  { "vcd",        3, "application/x-cdlink"              },
  { "vda",        3, "application/vda"                   },
  { "viv",        3, "video/vnd.vivo"                    },
  { "vivo",       4, "video/vnd.vivo"                    },
  { "vrml",       4, "model/vrml"                        },
  { "wav",        3, "audio/x-wav"                       },
  { "wax",        3, "audio/x-ms-wax"                    },

  { "wiki",       4, "text/x-fossil-wiki"                },
  { "wma",        3, "audio/x-ms-wma"                    },
  { "wmv",        3, "video/x-ms-wmv"                    },
  { "wmx",        3, "video/x-ms-wmx"                    },
  { "wrl",        3, "model/vrml"                        },
  { "wvx",        3, "video/x-ms-wvx"                    },
  { "xbm",        3, "image/x-xbitmap"                   },







>







267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  { "vcd",        3, "application/x-cdlink"              },
  { "vda",        3, "application/vda"                   },
  { "viv",        3, "video/vnd.vivo"                    },
  { "vivo",       4, "video/vnd.vivo"                    },
  { "vrml",       4, "model/vrml"                        },
  { "wav",        3, "audio/x-wav"                       },
  { "wax",        3, "audio/x-ms-wax"                    },
  { "webp",       4, "image/webp"                        },
  { "wiki",       4, "text/x-fossil-wiki"                },
  { "wma",        3, "audio/x-ms-wma"                    },
  { "wmv",        3, "video/x-ms-wmv"                    },
  { "wmx",        3, "video/x-ms-wmx"                    },
  { "wrl",        3, "model/vrml"                        },
  { "wvx",        3, "video/x-ms-wvx"                    },
  { "xbm",        3, "image/x-xbitmap"                   },
301
302
303
304
305
306
307





























































































308
309
310
311
312
313
314
  for(i=1; i<count(aMime); i++){
    if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){
      fossil_panic("mimetypes out of sequence: %s before %s",
                   aMime[i-1].zSuffix, aMime[i].zSuffix);
    }
  }
}






























































































/*
** Guess the mime-type of a document based on its name.
*/
const char *mimetype_from_name(const char *zName){
  const char *z;
  int i;







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







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
  for(i=1; i<count(aMime); i++){
    if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){
      fossil_panic("mimetypes out of sequence: %s before %s",
                   aMime[i-1].zSuffix, aMime[i].zSuffix);
    }
  }
}

/*
** Looks in the contents of the "mimetypes" setting for a suffix
** matching zSuffix. If found, it returns the configured value
** in memory owned by the app (i.e. do not free() it), else it
** returns 0.
**
** The mimetypes setting is expected to be a list of file extensions
** and mimetypes, with one such mapping per line. A leading '.'  on
** extensions is permitted for compatibility with lists imported from
** other tools which require them.
*/
static const char *mimetype_from_name_custom(const char *zSuffix){
  static char * zList = 0;
  static char const * zEnd = 0;
  static int once = 0;
  char * z;
  int tokenizerState /* 0=expecting a key, 1=skip next token,
                     ** 2=accept next token */;
  if(once==0){
    once = 1; 
    zList = db_get("mimetypes",0);
    if(zList==0){
      return 0;
    }
    /* Transform zList to simplify the main loop:
       replace non-newline spaces with NUL bytes. */
    zEnd = zList + strlen(zList);
    for(z = zList; z<zEnd; ++z){
      if('\n'==*z) continue;
      else if(fossil_isspace(*z)){
        *z = 0;
      }
    }
  }else if(zList==0){
    return 0;
  }
  tokenizerState = 0;
  z = zList;
  while( z<zEnd ){
    if(*z==0){
      ++z;
      continue;
    }
    else if('\n'==*z){
      if(2==tokenizerState){
        /* We were expecting a value for a successful match
           here, but got no value. Bail out. */
        break;
      }else{
        /* May happen on malformed inputs. Skip this record. */
        tokenizerState = 0;
        ++z;
        continue;
      }
    }
    switch(tokenizerState){
      case 0:{ /* This is a file extension */
        static char * zCase = 0;
        if('.'==*z){
          /*ignore an optional leading dot, for compatibility
            with some external mimetype lists*/;
          if(++z==zEnd){
            break;
          }
        }
        if(zCase<z){
          /*we have not yet case-folded this section: lower-case it*/
          for(zCase = z; zCase<zEnd && *zCase!=0; ++zCase){
            if(!(0x80 & *zCase)){
              *zCase = (char)fossil_tolower(*zCase);
            }
          }
        }
        if(strcmp(z,zSuffix)==0){
          tokenizerState = 2 /* Match: accept the next value. */;
        }else{
          tokenizerState = 1 /* No match: skip the next value. */;
        }
        z += strlen(z);
        break;
      }
      case 1: /* This is a value, but not a match. Skip it. */
        z += strlen(z);
        break;
      case 2: /* This is the value which matched the previous key. */;
        return z;
      default:
        assert(!"cannot happen - invalid tokenizerState value.");
    }
  }
  return 0;
}

/*
** Guess the mime-type of a document based on its name.
*/
const char *mimetype_from_name(const char *zName){
  const char *z;
  int i;
331
332
333
334
335
336
337




338
339
340
341
342
343
344
  for(i=0; zName[i]; i++){
    if( zName[i]=='.' ) z = &zName[i+1];
  }
  len = strlen(z);
  if( len<sizeof(zSuffix)-1 ){
    sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
    for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);




    first = 0;
    last = count(aMime) - 1;
    while( first<=last ){
      int c;
      i = (first+last)/2;
      c = fossil_strcmp(zSuffix, aMime[i].zSuffix);
      if( c==0 ) return aMime[i].zMimetype;







>
>
>
>







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  for(i=0; zName[i]; i++){
    if( zName[i]=='.' ) z = &zName[i+1];
  }
  len = strlen(z);
  if( len<sizeof(zSuffix)-1 ){
    sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
    for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
    z = mimetype_from_name_custom(zSuffix);
    if(z!=0){
      return z;
    }
    first = 0;
    last = count(aMime) - 1;
    while( first<=last ){
      int c;
      i = (first+last)/2;
      c = fossil_strcmp(zSuffix, aMime[i].zSuffix);
      if( c==0 ) return aMime[i].zMimetype;
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
** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test"
** filename is special and verifies the integrity of the mimetype table.
** It should return "ok".
*/
void mimetype_test_cmd(void){
  int i;
  mimetype_verify();

  for(i=2; i<g.argc; i++){
    fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
  }
}

/*
** WEBPAGE: mimetype_list
**
** Show the built-in table used to guess embedded document mimetypes
** from file suffixes.
*/
void mimetype_list_page(void){
  int i;



  mimetype_verify();
  style_header("Mimetype List");
  @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
  @ suffixes and the following table to guess at the appropriate mimetype
  @ for each document.</p>




































  @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
  @ data-column-types='tt' data-init-sort='1'>
  @ <thead>
  @ <tr><th>Suffix<th>Mimetype
  @ </thead>
  @ <tbody>
  for(i=0; i<count(aMime); i++){





    @ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
  }
  @ </tbody></table>
  style_table_sorter();
  style_footer();
}

/*







>













>
>
>



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







>
>
>
>
>
|







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test"
** filename is special and verifies the integrity of the mimetype table.
** It should return "ok".
*/
void mimetype_test_cmd(void){
  int i;
  mimetype_verify();
  db_find_and_open_repository(0, 0);
  for(i=2; i<g.argc; i++){
    fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
  }
}

/*
** WEBPAGE: mimetype_list
**
** Show the built-in table used to guess embedded document mimetypes
** from file suffixes.
*/
void mimetype_list_page(void){
  int i;
  char *zCustomList = 0;    /* value of the mimetypes setting */
  int nCustomEntries = 0;   /* number of entries in the mimetypes
                            ** setting */
  mimetype_verify();
  style_header("Mimetype List");
  @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
  @ suffixes and the following tables to guess at the appropriate mimetype
  @ for each document. Mimetypes may be customized and overridden using
  @ <a href="%R/help?cmd=mimetypes">the mimetypes config setting</a>.</p>
  zCustomList = db_get("mimetypes",0);
  if( zCustomList!=0 ){
    Blob list, entry, key, val;
    @ <h1>Repository-specific mimetypes</h1>
    @ <p>The following extension-to-mimetype mappings are defined via
    @ the <a href="%R/help?cmd=mimetypes">mimetypes setting</a>.</p>
    @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
    @ data-column-types='tt' data-init-sort='0'>
    @ <thead>
    @ <tr><th>Suffix<th>Mimetype
    @ </thead>
    @ <tbody>
    blob_set(&list, zCustomList);
    while( blob_line(&list, &entry)>0 ){
      const char *zKey;
      if( blob_token(&entry, &key)==0 ) continue;
      if( blob_token(&entry, &val)==0 ) continue;
      zKey = blob_str(&key);
      if( zKey[0]=='.' ) zKey++;
      @ <tr><td>%h(zKey)<td>%h(blob_str(&val))</tr>
      nCustomEntries++;
    }
    fossil_free(zCustomList);
    if( nCustomEntries==0 ){
      /* This can happen if the option is set to an empty/space-only
      ** value. */
      @ <tr><td colspan="2"><em>none</em></tr>
    }
    @ </tbody></table>
  }
  @ <h1>Default built-in mimetypes</h1>
  if(nCustomEntries>0){
    @ <p>Entries starting with an exclamation mark <em><strong>!</strong></em>
    @ are overwritten by repository-specific settings.</p>
  }
  @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
  @ data-column-types='tt' data-init-sort='1'>
  @ <thead>
  @ <tr><th>Suffix<th>Mimetype
  @ </thead>
  @ <tbody>
  for(i=0; i<count(aMime); i++){
    const char *zFlag = "";
    if(nCustomEntries>0 &&
       mimetype_from_name_custom(aMime[i].zSuffix)!=0){
      zFlag = "<em><strong>!</strong></em> ";
    }
    @ <tr><td>%s(zFlag)%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
  }
  @ </tbody></table>
  style_table_sorter();
  style_footer();
}

/*
504
505
506
507
508
509
510





























511
512
513
514
515
516
517

518
519

520



521
522
523
524
525
526
527
528
529
530
531
532

533
534
535
536












537
538
539
540
541
542
543
  rid = db_int(0, "SELECT rid FROM vcache"
                  " WHERE vid=%d AND fname=%Q", vid, zName);
  if( rid && content_get(rid, pContent)==0 ){
    rid = 0;
  }
  return rid;
}






























/*
** Transfer content to the output.  During the transfer, when text of
** the following form is seen:
**
**       href="$ROOT/
**       action="$ROOT/

**
** Convert $ROOT to the root URI of the repository.  Allow ' in place of "

** and any case for href or action.



*/
void convert_href_and_output(Blob *pIn){
  int i, base;
  int n = blob_size(pIn);
  char *z = blob_buffer(pIn);
  for(base=0, i=7; i<n; i++){
    if( z[i]=='$'
     && strncmp(&z[i],"$ROOT/", 6)==0
     && (z[i-1]=='\'' || z[i-1]=='"')
     && i-base>=9
     && ((fossil_strnicmp(&z[i-6],"href=",5)==0 && fossil_isspace(z[i-7])) ||
         (fossil_strnicmp(&z[i-8],"action=",7)==0 && fossil_isspace(z[i-9])) )

    ){
      blob_append(cgi_output_blob(), &z[base], i-base);
      blob_appendf(cgi_output_blob(), "%R");
      base = i+5;












    }
  }
  blob_append(cgi_output_blob(), &z[base], i-base);
}

/*
** Render a document as the reply to the HTTP request.  The body







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





|
|
>

|
>
|
>
>
>












>




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







647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
  rid = db_int(0, "SELECT rid FROM vcache"
                  " WHERE vid=%d AND fname=%Q", vid, zName);
  if( rid && content_get(rid, pContent)==0 ){
    rid = 0;
  }
  return rid;
}

/*
** Check to verify that z[i] is contained within HTML markup.
**
** This works by looking backwards in the string for the most recent
** '<' or '>' character.  If a '<' is found first, then we assume that
** z[i] is within markup.  If a '>' is seen or neither character is seen,
** then z[i] is not within markup.
*/
static int isWithinHtmlMarkup(const char *z, int i){
  while( i>=0 && z[i]!='>' && z[i]!='<' ){ i--; }
  return z[i]=='<';
}

/*
** Check to see if z[i] is contained within an href='...' of markup.
*/
static int isWithinHref(const char *z, int i){
  while( i>5
     && !fossil_isspace(z[i])
     && z[i]!='\'' && z[i]!='"'
     && z[i]!='>'
  ){ i--; }
  if( i<=6 ) return 0;
  if( z[i]!='\'' && z[i]!='\"' ) return 0;
  if( strncmp(&z[i-5],"href=",5)!=0 ) return 0;
  if( !fossil_isspace(z[i-6]) ) return 0;
  return 1;
}

/*
** Transfer content to the output.  During the transfer, when text of
** the following form is seen:
**
**       href="$ROOT/..."
**       action="$ROOT/..."
**       href=".../doc/$CURRENT/..."
**
** Convert $ROOT to the root URI of the repository, and $CURRENT to the 
** version number of the /doc/ document currently being displayed (if any).
** Allow ' in place of " and any case for href or action.  
**
** Efforts are made to limit this translation to cases where the text is
** fully contained with an HTML markup element.
*/
void convert_href_and_output(Blob *pIn){
  int i, base;
  int n = blob_size(pIn);
  char *z = blob_buffer(pIn);
  for(base=0, i=7; i<n; i++){
    if( z[i]=='$'
     && strncmp(&z[i],"$ROOT/", 6)==0
     && (z[i-1]=='\'' || z[i-1]=='"')
     && i-base>=9
     && ((fossil_strnicmp(&z[i-6],"href=",5)==0 && fossil_isspace(z[i-7])) ||
         (fossil_strnicmp(&z[i-8],"action=",7)==0 && fossil_isspace(z[i-9])) )
     && isWithinHtmlMarkup(z, i-6)
    ){
      blob_append(cgi_output_blob(), &z[base], i-base);
      blob_appendf(cgi_output_blob(), "%R");
      base = i+5;
    }else
    if( z[i]=='$'
     && strncmp(&z[i-5],"/doc/$CURRENT/", 11)==0
     && isWithinHref(z,i-5)
     && isWithinHtmlMarkup(z, i-5)
     && strncmp(g.zPath, "doc/",4)==0
    ){
      int j;
      for(j=7; g.zPath[j] && g.zPath[j]!='/'; j++){}
      blob_append(cgi_output_blob(), &z[base], i-base);
      blob_appendf(cgi_output_blob(), "%.*s", j-4, g.zPath+4);
      base = i+8;
    }
  }
  blob_append(cgi_output_blob(), &z[base], i-base);
}

/*
** Render a document as the reply to the HTTP request.  The body
604
605
606
607
608
609
610

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630



631
632
633
634
635
636
637
      Th_Render(blob_str(pBody));
    }
    if( !raw ){
      style_footer();
    }
#endif
  }else{

    cgi_set_content_type(zMime);
    cgi_set_content(pBody);
  }
}


/*
** WEBPAGE: uv
** WEBPAGE: doc
** URL: /uv/FILE
** URL: /doc/CHECKIN/FILE
**
** CHECKIN can be either tag or hash prefix or timestamp identifying a
** particular check, or the name of a branch (meaning the most recent
** check-in on that branch) or one of various magic words:
**
**     "tip"      means the most recent check-in
**
**     "ckout"    means the current check-out, if the server is run from
**                within a check-out, otherwise it is the same as "tip"



**
** FILE is the name of a file to delivered up as a webpage.  FILE is relative
** to the root of the source tree of the repository. The FILE must
** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read
** directly from disk and need not be a managed file.
**
** The "ckout" CHECKIN is intended for development - to provide a mechanism







>




















>
>
>







794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
      Th_Render(blob_str(pBody));
    }
    if( !raw ){
      style_footer();
    }
#endif
  }else{
    fossil_free(style_csp(1));
    cgi_set_content_type(zMime);
    cgi_set_content(pBody);
  }
}


/*
** WEBPAGE: uv
** WEBPAGE: doc
** URL: /uv/FILE
** URL: /doc/CHECKIN/FILE
**
** CHECKIN can be either tag or hash prefix or timestamp identifying a
** particular check, or the name of a branch (meaning the most recent
** check-in on that branch) or one of various magic words:
**
**     "tip"      means the most recent check-in
**
**     "ckout"    means the current check-out, if the server is run from
**                within a check-out, otherwise it is the same as "tip"
**
**     "latest"   means use the most recent check-in for the document
**                regardless of what branch it occurs on.
**
** FILE is the name of a file to delivered up as a webpage.  FILE is relative
** to the root of the source tree of the repository. The FILE must
** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read
** directly from disk and need not be a managed file.
**
** The "ckout" CHECKIN is intended for development - to provide a mechanism
694
695
696
697
698
699
700










701
702
703
704
705
706
707
      i = 0;
    }else{
      if( zName==0 || zName[0]==0 ) zName = "tip/index.wiki";
      for(i=0; zName[i] && zName[i]!='/'; i++){}
      zCheckin = mprintf("%.*s", i, zName);
      if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){
        zCheckin = "tip";










      }
    }
    if( nMiss==count(azSuffix) ){
      zName = "404.md";
      zDfltTitle = "Not Found";
    }else if( zName[i]==0 ){
      assert( nMiss>=0 && nMiss<count(azSuffix) );







>
>
>
>
>
>
>
>
>
>







888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
      i = 0;
    }else{
      if( zName==0 || zName[0]==0 ) zName = "tip/index.wiki";
      for(i=0; zName[i] && zName[i]!='/'; i++){}
      zCheckin = mprintf("%.*s", i, zName);
      if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){
        zCheckin = "tip";
      }else if( fossil_strcmp(zCheckin,"latest")==0 ){
        char *zNewCkin = db_text(0,
          "SELECT uuid FROM blob, mlink, event, filename"
          " WHERE filename.name=%Q"
          "   AND mlink.fnid=filename.fnid"
          "   AND blob.rid=mlink.mid"
          "   AND event.objid=mlink.mid"
          " ORDER BY event.mtime DESC LIMIT 1",
          zName + i + 1);
        if( zNewCkin ) zCheckin = zNewCkin;
      }
    }
    if( nMiss==count(azSuffix) ){
      zName = "404.md";
      zDfltTitle = "Not Found";
    }else if( zName[i]==0 ){
      assert( nMiss>=0 && nMiss<count(azSuffix) );
917
918
919
920
921
922
923
























924
925
926
927
928
929
930
  if( blob_size(&bgimg)==0 ){
    blob_init(&bgimg, (char*)aBackground, sizeof(aBackground));
  }
  cgi_set_content_type(zMime);
  cgi_set_content(&bgimg);
}


























/*
** WEBPAGE: docsrch
**
** Search for documents that match a user-supplied full-text search pattern.
** If no pattern is specified (by the s= query parameter) then the user
** is prompted to enter a search string.







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







1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
  if( blob_size(&bgimg)==0 ){
    blob_init(&bgimg, (char*)aBackground, sizeof(aBackground));
  }
  cgi_set_content_type(zMime);
  cgi_set_content(&bgimg);
}


/*
** WEBPAGE: favicon.ico
**
** Return the default favicon.ico image.  The returned image is for the
** Fossil lizard icon.
**
** The intended use case here is to supply a favicon for the "fossil ui"
** command.  For a permanent website, the recommended process is for
** the admin to set up a project-specific favicon and reference that
** icon in the HTML header using a line like:
**
**   <link rel="icon" href="URL-FOR-YOUR-ICON" type="MIMETYPE"/>
** 
*/
void favicon_page(void){
  Blob favicon;

  etag_check(ETAG_CONFIG, 0);
  blob_zero(&favicon);
  blob_init(&favicon, (char*)aLogo, sizeof(aLogo));
  cgi_set_content_type("image/gif");
  cgi_set_content(&favicon);
}

/*
** WEBPAGE: docsrch
**
** Search for documents that match a user-supplied full-text search pattern.
** If no pattern is specified (by the s= query parameter) then the user
** is prompted to enter a search string.
Changes to src/export.c.
1383
1384
1385
1386
1387
1388
1389



1390

1391
1392
1393
1394
1395
1396
1397
      if( xCmd==0 ) fossil_fatal("cannot open file \"%s\" for writing", zDebug);
    }
  }else{
    zCmd = mprintf("git fast-import"
              " --export-marks=.mirror_state/marks.txt"
              " --quiet --done");
    gitmirror_message(VERB_NORMAL, "%s\n", zCmd);



    xCmd = popen(zCmd, "w");

    if( zCmd==0 ){
      fossil_fatal("cannot start the \"git fast-import\" command");
    }
    fossil_free(zCmd);
  }

  /* Run the export */







>
>
>

>







1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
      if( xCmd==0 ) fossil_fatal("cannot open file \"%s\" for writing", zDebug);
    }
  }else{
    zCmd = mprintf("git fast-import"
              " --export-marks=.mirror_state/marks.txt"
              " --quiet --done");
    gitmirror_message(VERB_NORMAL, "%s\n", zCmd);
#ifdef _WIN32
    xCmd = popen(zCmd, "wb");
#else
    xCmd = popen(zCmd, "w");
#endif
    if( zCmd==0 ){
      fossil_fatal("cannot start the \"git fast-import\" command");
    }
    fossil_free(zCmd);
  }

  /* Run the export */
Changes to src/extcgi.c.
96
97
98
99
100
101
102

































103
104
105
106
107
108
109
    if( !fossil_isalnum(c) && c!='_' && c!='-' && c!='.' && c!='/' ){
      zFailReason = "illegal character in path";
      break;
    }
  }
  return zFailReason;
}


































/*
** WEBPAGE: ext  raw-content
**
** Relay an HTTP request to secondary CGI after first checking the
** login credentials and setting auxiliary environment variables
** so that the secondary CGI can be aware of the credentials and







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







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
    if( !fossil_isalnum(c) && c!='_' && c!='-' && c!='.' && c!='/' ){
      zFailReason = "illegal character in path";
      break;
    }
  }
  return zFailReason;
}

/*
** The *pzPath input is a pathname obtained from mprintf().
**
** If
**
**   (1) zPathname is the name of a directory, and
**   (2) the name ends with "/", and
**   (3) the directory contains a file named index.html, index.wiki,
**       or index.md (in that order)
**
** then replace the input with a revised name that includes the index.*
** file and return non-zero (true).  If any condition is not met, return
** zero and leave the input pathname unchanged.
*/
static int isDirWithIndexFile(char **pzPath){
  static const char *azIndexNames[] = {
    "index.html", "index.wiki", "index.md"
  };
  int i;
  if( file_isdir(*pzPath, ExtFILE)!=1 ) return 0;
  if( sqlite3_strglob("*/", *pzPath)!=0 ) return 0;
  for(i=0; i<sizeof(azIndexNames)/sizeof(azIndexNames[0]); i++){
    char *zNew = mprintf("%s%s", *pzPath, azIndexNames[i]);
    if( file_isfile(zNew, ExtFILE) ){
      fossil_free(*pzPath);
      *pzPath = zNew;
      return 1;
    }
    fossil_free(zNew);
  }
  return 0;
}

/*
** WEBPAGE: ext  raw-content
**
** Relay an HTTP request to secondary CGI after first checking the
** login credentials and setting auxiliary environment variables
** so that the secondary CGI can be aware of the credentials and
118
119
120
121
122
123
124





125
126
127
128
129
130
131
** static content.
**
** The path after the /ext is the path to the CGI script or static file
** relative to DIR. For security, this path may not contain characters
** other than ASCII letters or digits, ".", "-", "/", and "_".  If the
** "." or "-" characters are present in the path then they may not follow
** a "/".





*/
void ext_page(void){
  const char *zName = P("name");  /* Path information after /ext */
  char *zPath = 0;                /* Complete path from extroot */
  int nRoot;                      /* Number of bytes in the extroot name */
  char *zScript = 0;              /* Name of the CGI script */
  int nScript = 0;                /* Bytes in the CGI script name */







>
>
>
>
>







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
** static content.
**
** The path after the /ext is the path to the CGI script or static file
** relative to DIR. For security, this path may not contain characters
** other than ASCII letters or digits, ".", "-", "/", and "_".  If the
** "." or "-" characters are present in the path then they may not follow
** a "/".
**
** If the path after /ext ends with "/" and is the name of a directory then
** that directory is searched for files named "index.html", "index.wiki",
** and "index.md" (in that order) and if found, those filenames are
** appended to the path.
*/
void ext_page(void){
  const char *zName = P("name");  /* Path information after /ext */
  char *zPath = 0;                /* Complete path from extroot */
  int nRoot;                      /* Number of bytes in the extroot name */
  char *zScript = 0;              /* Name of the CGI script */
  int nScript = 0;                /* Bytes in the CGI script name */
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  zFailReason = "???";
  if( file_isdir(g.zExtRoot,ExtFILE)!=1 ){
    zFailReason = "extroot is not a directory";
    goto ext_not_found;
  }
  zPath = mprintf("%s/%s", g.zExtRoot, zName);
  nRoot = (int)strlen(g.zExtRoot);
  if( file_isfile(zPath, ExtFILE) ){
    nScript = (int)strlen(zPath);
    zScript = zPath;
  }else{
    for(i=nRoot+1; zPath[i]; i++){
      char c = zPath[i];
      if( c=='/' ){
        int isDir, isFile;







|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  zFailReason = "???";
  if( file_isdir(g.zExtRoot,ExtFILE)!=1 ){
    zFailReason = "extroot is not a directory";
    goto ext_not_found;
  }
  zPath = mprintf("%s/%s", g.zExtRoot, zName);
  nRoot = (int)strlen(g.zExtRoot);
  if( file_isfile(zPath, ExtFILE) || isDirWithIndexFile(&zPath) ){
    nScript = (int)strlen(zPath);
    zScript = zPath;
  }else{
    for(i=nRoot+1; zPath[i]; i++){
      char c = zPath[i];
      if( c=='/' ){
        int isDir, isFile;
Changes to src/file.c.
345
346
347
348
349
350
351








































352
353
354
355
356
357
358
  }else{
    rc = 2; /* It exists and is something else. */
  }
  free(zFN);
  return rc;
}










































/*
** Wrapper around the access() system call.
*/
int file_access(const char *zFilename, int flags){
  int rc;
  void *zMbcs = fossil_utf8_to_path(zFilename, 0);







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







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
  }else{
    rc = 2; /* It exists and is something else. */
  }
  free(zFN);
  return rc;
}

/*
** Return true (1) if zFilename seems like it seems like a valid
** repository database.
*/
int file_is_repository(const char *zFilename){
  i64 sz;
  sqlite3 *db = 0;
  sqlite3_stmt *pStmt = 0;
  int rc;
  int i;
  static const char *azReqTab[] = {
     "blob", "delta", "rcvfrom", "user", "config"
  };
  if( !file_isfile(zFilename, ExtFILE) ) return 0;
  sz = file_size(zFilename, ExtFILE);
  if( sz<35328 ) return 0;
  if( sz%512!=0 ) return 0;
  rc = sqlite3_open_v2(zFilename, &db, 
          SQLITE_OPEN_READWRITE, 0);
  if( rc!=0 ) goto not_a_repo;
  for(i=0; i<count(azReqTab); i++){
    if( sqlite3_table_column_metadata(db, "main", azReqTab[i],0,0,0,0,0,0) ){
      goto not_a_repo;
    }
  }
  rc = sqlite3_prepare_v2(db, "SELECT 1 FROM config WHERE name='project-code'",
                          -1, &pStmt, 0);
  if( rc ) goto not_a_repo;
  rc = sqlite3_step(pStmt);
  if( rc!=SQLITE_ROW ) goto not_a_repo;
  sqlite3_finalize(pStmt);
  sqlite3_close(db);
  return 1;

not_a_repo:
  sqlite3_finalize(pStmt);
  sqlite3_close(db);
  return 0;
}


/*
** Wrapper around the access() system call.
*/
int file_access(const char *zFilename, int flags){
  int rc;
  void *zMbcs = fossil_utf8_to_path(zFilename, 0);
497
498
499
500
501
502
503

504
505
506
507
508
509
510
  out = fossil_fopen(zTo, "wb");
  if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo);
  while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){
    fwrite(zBuf, 1, got, out);
  }
  fclose(in);
  fclose(out);

}

/*
** COMMAND: test-file-copy
**
** Usage: %fossil test-file-copy SOURCE DESTINATION
**







>







537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  out = fossil_fopen(zTo, "wb");
  if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo);
  while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){
    fwrite(zBuf, 1, got, out);
  }
  fclose(in);
  fclose(out);
  if( file_isexe(zFrom, ExtFILE) ) file_setexe(zTo, 1);
}

/*
** COMMAND: test-file-copy
**
** Usage: %fossil test-file-copy SOURCE DESTINATION
**
1096
1097
1098
1099
1100
1101
1102



























































1103
1104
1105
1106
1107
1108
1109
      zOut[0] = fossil_toupper(zOut[0]);
    }
  }
#endif
  blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
                                       blob_size(pOut), slash));
}




























































/*
** Emits the effective or raw stat() information for the specified
** file or directory, optionally preserving the trailing slash and
** resetting the cached stat() information.
*/
static void emitFileStat(







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







1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
      zOut[0] = fossil_toupper(zOut[0]);
    }
  }
#endif
  blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
                                       blob_size(pOut), slash));
}

/*
** The input is the name of an executable, such as one might
** type on a command-line.  This routine resolves that name into
** a full pathname.  The result is obtained from fossil_malloc()
** and should be freed by the caller.
**
** This routine only works on unix.  On Windows, simply return
** a copy of the input.
*/
char *file_fullexename(const char *zCmd){
#ifdef _WIN32
  return fossil_strdup(zCmd);
#else
  char *zPath;
  char *z;
  if( zCmd[0]=='/' ){
    return fossil_strdup(zCmd);
  }
  if( strchr(zCmd,'/')!=0 ){
    Blob out = BLOB_INITIALIZER;
    file_canonical_name(zCmd, &out, 0);
    z = fossil_strdup(blob_str(&out));
    blob_reset(&out);
    return z;
  }
  zPath = fossil_getenv("PATH");
  while( zPath && zPath[0] ){
    int n;
    char *zColon;
    zColon = strchr(zPath, ':');
    n = zColon ? (int)(zColon-zPath) : (int)strlen(zPath);
    z = mprintf("%.*s/%s", n, zPath, zCmd);
    if( file_isexe(z, ExtFILE) ){
      return z;
    }
    fossil_free(z);
    if( zColon==0 ) break;
    zPath = zColon+1;
  }
  return fossil_strdup(zCmd);
#endif
}

/*
** COMMAND: test-which
**
** Usage: %fossil test-which ARGS...
**
** For each argument, search the PATH for the executable with the name
** and print its full pathname.
*/
void test_which_cmd(void){
  int i;
  for(i=2; i<g.argc; i++){
    char *z = file_fullexename(g.argv[i]);
    fossil_print("%z\n", z);
  }
}

/*
** Emits the effective or raw stat() information for the specified
** file or directory, optionally preserving the trailing slash and
** resetting the cached stat() information.
*/
static void emitFileStat(
1123
1124
1125
1126
1127
1128
1129

1130
1131
1132
1133
1134
1135
1136
  fossil_print("[%s] -> [%s]\n", zPath, blob_buffer(&x));
  blob_reset(&x);
  memset(&testFileStat, 0, sizeof(struct fossilStat));
  rc = fossil_stat(zPath, &testFileStat, 0);
  fossil_print("  stat_rc                = %d\n", rc);
  sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size);
  fossil_print("  stat_size              = %s\n", zBuf);

  z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime);
  sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", testFileStat.st_mtime, z);
  fossil_free(z);
  fossil_print("  stat_mtime             = %s\n", zBuf);
  fossil_print("  stat_mode              = 0%o\n", testFileStat.st_mode);
  memset(&testFileStat, 0, sizeof(struct fossilStat));
  rc = fossil_stat(zPath, &testFileStat, 1);







>







1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
  fossil_print("[%s] -> [%s]\n", zPath, blob_buffer(&x));
  blob_reset(&x);
  memset(&testFileStat, 0, sizeof(struct fossilStat));
  rc = fossil_stat(zPath, &testFileStat, 0);
  fossil_print("  stat_rc                = %d\n", rc);
  sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size);
  fossil_print("  stat_size              = %s\n", zBuf);
  if( g.db==0 ) sqlite3_open(":memory:", &g.db);
  z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime);
  sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", testFileStat.st_mtime, z);
  fossil_free(z);
  fossil_print("  stat_mtime             = %s\n", zBuf);
  fossil_print("  stat_mode              = 0%o\n", testFileStat.st_mode);
  memset(&testFileStat, 0, sizeof(struct fossilStat));
  rc = fossil_stat(zPath, &testFileStat, 1);
1163
1164
1165
1166
1167
1168
1169

1170
1171
1172
1173
1174
1175
1176
  fossil_print("  file_mtime(RepoFILE)   = %s\n", zBuf);
  fossil_print("  file_mode(RepoFILE)    = 0%o\n", file_mode(zPath,RepoFILE));
  fossil_print("  file_isfile(RepoFILE)  = %d\n", file_isfile(zPath,RepoFILE));
  fossil_print("  file_isfile_or_link    = %d\n", file_isfile_or_link(zPath));
  fossil_print("  file_islink            = %d\n", file_islink(zPath));
  fossil_print("  file_isexe(RepoFILE)   = %d\n", file_isexe(zPath,RepoFILE));
  fossil_print("  file_isdir(RepoFILE)   = %d\n", file_isdir(zPath,RepoFILE));

  if( reset ) resetStat();
}

/*
** COMMAND: test-file-environment
**
** Usage: %fossil test-file-environment FILENAME...







>







1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
  fossil_print("  file_mtime(RepoFILE)   = %s\n", zBuf);
  fossil_print("  file_mode(RepoFILE)    = 0%o\n", file_mode(zPath,RepoFILE));
  fossil_print("  file_isfile(RepoFILE)  = %d\n", file_isfile(zPath,RepoFILE));
  fossil_print("  file_isfile_or_link    = %d\n", file_isfile_or_link(zPath));
  fossil_print("  file_islink            = %d\n", file_islink(zPath));
  fossil_print("  file_isexe(RepoFILE)   = %d\n", file_isexe(zPath,RepoFILE));
  fossil_print("  file_isdir(RepoFILE)   = %d\n", file_isdir(zPath,RepoFILE));
  fossil_print("  file_is_repository     = %d\n", file_is_repository(zPath));
  if( reset ) resetStat();
}

/*
** COMMAND: test-file-environment
**
** Usage: %fossil test-file-environment FILENAME...
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
  int i;
  int slashFlag = find_option("slash",0,0)!=0;
  int resetFlag = find_option("reset",0,0)!=0;
  const char *zAllow = find_option("allow-symlinks",0,1);
  if( find_option("open-config", 0, 0)!=0 ){
    Th_OpenConfig(1);
  }
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  fossil_print("filenames_are_case_sensitive() = %d\n",
               filenames_are_case_sensitive());
  fossil_print("db_allow_symlinks_by_default() = %d\n",
               db_allow_symlinks_by_default());
  if( zAllow ){
    g.allowSymlinks = !is_false(zAllow);
  }







|







1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
  int i;
  int slashFlag = find_option("slash",0,0)!=0;
  int resetFlag = find_option("reset",0,0)!=0;
  const char *zAllow = find_option("allow-symlinks",0,1);
  if( find_option("open-config", 0, 0)!=0 ){
    Th_OpenConfig(1);
  }
  db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0);
  fossil_print("filenames_are_case_sensitive() = %d\n",
               filenames_are_case_sensitive());
  fossil_print("db_allow_symlinks_by_default() = %d\n",
               db_allow_symlinks_by_default());
  if( zAllow ){
    g.allowSymlinks = !is_false(zAllow);
  }
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
    }
  }else{
    rc = 1;
  }
  return rc;
#else
  extern char **environ;
  environ = 0;
  return 0;
#endif
}

/*
** Like fopen() but always takes a UTF8 argument.
**







|







1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
    }
  }else{
    rc = 1;
  }
  return rc;
#else
  extern char **environ;
  environ[0] = 0;
  return 0;
#endif
}

/*
** Like fopen() but always takes a UTF8 argument.
**
1806
1807
1808
1809
1810
1811
1812



















































1813
1814
1815
1816
1817
1818
1819
  fossil_path_free(uName);
  fossil_unicode_free(uMode);
#else
  FILE *f = fopen(zName, zMode);
#endif
  return f;
}




















































/*
** Return non-NULL if zFilename contains pathname elements that
** are reserved on Windows.  The returned string is the disallowed
** path element.
*/
const char *file_is_win_reserved(const char *zPath){







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







1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
  fossil_path_free(uName);
  fossil_unicode_free(uMode);
#else
  FILE *f = fopen(zName, zMode);
#endif
  return f;
}

/*
** Works like fclose() except that:
**
** 1) is a no-op if f is 0 or if it is stdin.
**
** 2) If f is one of (stdout, stderr), it is flushed but not closed.
*/
void fossil_fclose(FILE *f){
  if(f!=0){
    if(stdout==f || stderr==f){
      fflush(f);
    }else if(stdin!=f){
      fclose(f);
    }
  }
}

/*
**   Works like fopen(zName,"wb") except that:
**
**   1) If zName is "-", the stdout handle is returned.
**
**   2) Else file_mkfolder() is used to create all directories
**      which lead up to the file before opening it.
**
**   3) It fails fatally if the file cannot be opened.
*/
FILE *fossil_fopen_for_output(const char *zFilename){
  if(zFilename[0]=='-' && zFilename[1]==0){
    return stdout;
  }else{
    FILE * p;
    file_mkfolder(zFilename, ExtFILE, 1, 0);
    p = fossil_fopen(zFilename, "wb");
    if( p==0 ){
#if _WIN32
      const char *zReserved = file_is_win_reserved(zFilename);
      if( zReserved ){
        fossil_fatal("cannot open \"%s\" because \"%s\" is "
                     "a reserved name on Windows", zFilename,
                     zReserved);
      }
#endif
      fossil_fatal("unable to open file \"%s\" for writing",
                   zFilename);
    }
    return p;
  }
}


/*
** Return non-NULL if zFilename contains pathname elements that
** are reserved on Windows.  The returned string is the disallowed
** path element.
*/
const char *file_is_win_reserved(const char *zPath){
Changes to src/forum.c.
55
56
57
58
59
60
61

















62
63
64
65
66
67
68
  ForumEntry *pFirst;    /* First entry in chronological order */
  ForumEntry *pLast;     /* Last entry in chronological order */
  ForumEntry *pDisplay;  /* Entries in display order */
  ForumEntry *pTail;     /* Last on the display list */
  int mxIndent;          /* Maximum indentation level */
};
#endif /* INTERFACE */


















/*
** Delete a complete ForumThread and all its entries.
*/
static void forumthread_delete(ForumThread *pThread){
  ForumEntry *pEntry, *pNext;
  for(pEntry=pThread->pFirst; pEntry; pEntry = pNext){







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







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  ForumEntry *pFirst;    /* First entry in chronological order */
  ForumEntry *pLast;     /* Last entry in chronological order */
  ForumEntry *pDisplay;  /* Entries in display order */
  ForumEntry *pTail;     /* Last on the display list */
  int mxIndent;          /* Maximum indentation level */
};
#endif /* INTERFACE */

/*
** Return true if the forum entry with the given rid has been
** subsequently edited.
*/
int forum_rid_has_been_edited(int rid){
  static Stmt q;
  int res;
  db_static_prepare(&q,
     "SELECT 1 FROM forumpost A, forumpost B"
     " WHERE A.fpid=$rid AND B.froot=A.froot AND B.fprev=$rid"
  );
  db_bind_int(&q, "$rid", rid);
  res = db_step(&q)==SQLITE_ROW;
  db_reset(&q);
  return res;
}

/*
** Delete a complete ForumThread and all its entries.
*/
static void forumthread_delete(ForumThread *pThread){
  ForumEntry *pEntry, *pNext;
  for(pEntry=pThread->pFirst; pEntry; pEntry = pNext){
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

163
164
165
166
167




168
169
170

171
172
173
174
175
176
177
** Construct a ForumThread object given the root record id.
*/
static ForumThread *forumthread_create(int froot, int computeHierarchy){
  ForumThread *pThread;
  ForumEntry *pEntry;
  Stmt q;
  int sid = 1;

  pThread = fossil_malloc( sizeof(*pThread) );
  memset(pThread, 0, sizeof(*pThread));
  db_prepare(&q,
     "SELECT fpid, firt, fprev, (SELECT uuid FROM blob WHERE rid=fpid)"
     "  FROM forumpost"
     " WHERE froot=%d ORDER BY fmtime",
     froot
  );
  while( db_step(&q)==SQLITE_ROW ){
    pEntry = fossil_malloc( sizeof(*pEntry) );
    memset(pEntry, 0, sizeof(*pEntry));
    pEntry->fpid = db_column_int(&q, 0);
    pEntry->firt = db_column_int(&q, 1);
    pEntry->fprev = db_column_int(&q, 2);
    pEntry->zUuid = fossil_strdup(db_column_text(&q,3));
    pEntry->mfirt = pEntry->firt;
    pEntry->sid = sid++;
    pEntry->pPrev = pThread->pLast;
    pEntry->pNext = 0;

    if( pThread->pLast==0 ){
      pThread->pFirst = pEntry;
    }else{
      pThread->pLast->pNext = pEntry;
    }




    pThread->pLast = pEntry;
  }
  db_finalize(&q);


  /* Establish which entries are the latest edit.  After this loop
  ** completes, entries that have non-NULL pLeaf should not be
  ** displayed.
  */
  for(pEntry=pThread->pFirst; pEntry; pEntry=pEntry->pNext){
    if( pEntry->fprev ){







>



















>





>
>
>
>



>







154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
** Construct a ForumThread object given the root record id.
*/
static ForumThread *forumthread_create(int froot, int computeHierarchy){
  ForumThread *pThread;
  ForumEntry *pEntry;
  Stmt q;
  int sid = 1;
  Bag seen = Bag_INIT;
  pThread = fossil_malloc( sizeof(*pThread) );
  memset(pThread, 0, sizeof(*pThread));
  db_prepare(&q,
     "SELECT fpid, firt, fprev, (SELECT uuid FROM blob WHERE rid=fpid)"
     "  FROM forumpost"
     " WHERE froot=%d ORDER BY fmtime",
     froot
  );
  while( db_step(&q)==SQLITE_ROW ){
    pEntry = fossil_malloc( sizeof(*pEntry) );
    memset(pEntry, 0, sizeof(*pEntry));
    pEntry->fpid = db_column_int(&q, 0);
    pEntry->firt = db_column_int(&q, 1);
    pEntry->fprev = db_column_int(&q, 2);
    pEntry->zUuid = fossil_strdup(db_column_text(&q,3));
    pEntry->mfirt = pEntry->firt;
    pEntry->sid = sid++;
    pEntry->pPrev = pThread->pLast;
    pEntry->pNext = 0;
    bag_insert(&seen, pEntry->fpid);
    if( pThread->pLast==0 ){
      pThread->pFirst = pEntry;
    }else{
      pThread->pLast->pNext = pEntry;
    }
    if( pEntry->firt && !bag_find(&seen,pEntry->firt) ){
      pEntry->firt = froot;
      pEntry->mfirt = froot;
    }
    pThread->pLast = pEntry;
  }
  db_finalize(&q);
  bag_clear(&seen);

  /* Establish which entries are the latest edit.  After this loop
  ** completes, entries that have non-NULL pLeaf should not be
  ** displayed.
  */
  for(pEntry=pThread->pFirst; pEntry; pEntry=pEntry->pNext){
    if( pEntry->fprev ){
197
198
199
200
201
202
203


























204
205
206
207
208
209
210



211
212
213
214
215
216
217
218
219
220




221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237


238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264

265
266
267
268
269
270
271
272
273
274
275
276
277





278
279
280
281

282
283
284
285
286
287
288
    forumentry_add_to_display(pThread, pEntry);
    forumthread_display_order(pThread, pEntry);
  }

  /* Return the result */
  return pThread;
}



























/*
** COMMAND: test-forumthread
**
** Usage: %fossil test-forumthread THREADID
**
** Display a summary of all messages on a thread.



*/
void forumthread_cmd(void){
  int fpid;
  int froot;
  const char *zName;
  ForumThread *pThread;
  ForumEntry *p;

  db_find_and_open_repository(0,0);
  verify_all_options();




  if( g.argc!=3 ) usage("THREADID");
  zName = g.argv[2];
  fpid = symbolic_name_to_rid(zName, "f");
  if( fpid<=0 ){
    fpid = db_int(0, "SELECT rid FROM blob WHERE rid=%d", atoi(zName));
  }
  if( fpid<=0 ){
    fossil_fatal("Unknown or ambiguous forum id: \"%s\"", zName);
  }
  froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
  if( froot==0 ){
    fossil_fatal("Not a forum post: \"%s\"", zName);
  }
  fossil_print("fpid  = %d\n", fpid);
  fossil_print("froot = %d\n", froot);
  pThread = forumthread_create(froot, 1);
  fossil_print("Chronological:\n");


           /*   123456789 123456789 123456789 123456789 123456789 123456789  */
  fossil_print("     fpid      firt     fprev     mfirt     pLeaf    nReply\n");
  for(p=pThread->pFirst; p; p=p->pNext){
    fossil_print("%9d %9d %9d %9d %9d %9d\n",
       p->fpid, p->firt, p->fprev, p->mfirt, p->pLeaf ? p->pLeaf->fpid : 0,
       p->nReply);
  }
  fossil_print("\nDisplay\n");
  for(p=pThread->pDisplay; p; p=p->pDisplay){
    fossil_print("%*s", (p->nIndent-1)*3, "");
    if( p->pLeaf ){
      fossil_print("%d->%d\n", p->fpid, p->pLeaf->fpid);
    }else{
      fossil_print("%d\n", p->fpid);
    }
  }
  forumthread_delete(pThread);
}

/*
** Render a forum post for display
*/
void forum_render(
  const char *zTitle,         /* The title.  Might be NULL for no title */
  const char *zMimetype,      /* Mimetype of the message */
  const char *zContent,       /* Content of the message */
  const char *zClass          /* Put in a <div> if not NULL */

){
  if( zClass ){
    @ <div class='%s(zClass)'>
  }
  if( zTitle ){
    if( zTitle[0] ){
      @ <h1>%h(zTitle)</h1>
    }else{
      @ <h1><i>Deleted</i></h1>
    }
  }
  if( zContent && zContent[0] ){
    Blob x;





    blob_init(&x, 0, 0);
    blob_append(&x, zContent, -1);
    wiki_render_by_mimetype(&x, zMimetype);
    blob_reset(&x);

  }else{
    @ <i>Deleted</i>
  }
  if( zClass ){
    @ </div>
  }
}







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




|

|
>
>
>










>
>
>
>

















>
>
|
|

|

|




















|
>













>
>
>
>
>




>







221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
    forumentry_add_to_display(pThread, pEntry);
    forumthread_display_order(pThread, pEntry);
  }

  /* Return the result */
  return pThread;
}

/*
** List all forum threads to standard output.
*/
static void forum_thread_list(void){
  Stmt q;
  db_prepare(&q,
    " SELECT"
    "  datetime(max(fmtime)),"
    "  sum(fprev IS NULL),"
    "  froot"
    " FROM forumpost"
    " GROUP BY froot"
    " ORDER BY 1;"
  );
  fossil_print("    id  cnt    most recent post\n");
  fossil_print("------ ---- -------------------\n");
  while( db_step(&q)==SQLITE_ROW ){
    fossil_print("%6d %4d %s\n",
      db_column_int(&q, 2),
      db_column_int(&q, 1),
      db_column_text(&q, 0)
    );
  }
  db_finalize(&q);
}

/*
** COMMAND: test-forumthread
**
** Usage: %fossil test-forumthread [THREADID]
**
** Display a summary of all messages on a thread THREADID.  If the
** THREADID argument is omitted, then show a list of all threads.
**
** This command is intended for testing an analysis only.
*/
void forumthread_cmd(void){
  int fpid;
  int froot;
  const char *zName;
  ForumThread *pThread;
  ForumEntry *p;

  db_find_and_open_repository(0,0);
  verify_all_options();
  if( g.argc==2 ){
    forum_thread_list();
    return;
  }
  if( g.argc!=3 ) usage("THREADID");
  zName = g.argv[2];
  fpid = symbolic_name_to_rid(zName, "f");
  if( fpid<=0 ){
    fpid = db_int(0, "SELECT rid FROM blob WHERE rid=%d", atoi(zName));
  }
  if( fpid<=0 ){
    fossil_fatal("Unknown or ambiguous forum id: \"%s\"", zName);
  }
  froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
  if( froot==0 ){
    fossil_fatal("Not a forum post: \"%s\"", zName);
  }
  fossil_print("fpid  = %d\n", fpid);
  fossil_print("froot = %d\n", froot);
  pThread = forumthread_create(froot, 1);
  fossil_print("Chronological:\n");
  fossil_print(
/* 0         1         2         3         4         5         6         7    */
/*  123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */
  " sid      fpid      firt     fprev     mfirt     pLeaf  nReply  hash\n");
  for(p=pThread->pFirst; p; p=p->pNext){
    fossil_print("%4d %9d %9d %9d %9d %9d  %6d  %8.8s\n", p->sid,
       p->fpid, p->firt, p->fprev, p->mfirt, p->pLeaf ? p->pLeaf->fpid : 0,
       p->nReply, p->zUuid);
  }
  fossil_print("\nDisplay\n");
  for(p=pThread->pDisplay; p; p=p->pDisplay){
    fossil_print("%*s", (p->nIndent-1)*3, "");
    if( p->pLeaf ){
      fossil_print("%d->%d\n", p->fpid, p->pLeaf->fpid);
    }else{
      fossil_print("%d\n", p->fpid);
    }
  }
  forumthread_delete(pThread);
}

/*
** Render a forum post for display
*/
void forum_render(
  const char *zTitle,         /* The title.  Might be NULL for no title */
  const char *zMimetype,      /* Mimetype of the message */
  const char *zContent,       /* Content of the message */
  const char *zClass,         /* Put in a <div> if not NULL */
  int bScroll                 /* Large message content scrolls if true */
){
  if( zClass ){
    @ <div class='%s(zClass)'>
  }
  if( zTitle ){
    if( zTitle[0] ){
      @ <h1>%h(zTitle)</h1>
    }else{
      @ <h1><i>Deleted</i></h1>
    }
  }
  if( zContent && zContent[0] ){
    Blob x;
    if( bScroll ){
      @ <div class='forumPostBody'>
    }else{
      @ <div class='forumPostFullBody'>
    }
    blob_init(&x, 0, 0);
    blob_append(&x, zContent, -1);
    wiki_render_by_mimetype(&x, zMimetype);
    blob_reset(&x);
    @ </div>
  }else{
    @ <i>Deleted</i>
  }
  if( zClass ){
    @ </div>
  }
}
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
  @ <br>
  @ <label><input type="checkbox" name="trust">
  @ Trust user "%h(pPost->zUser)"
  @ so that future posts by "%h(pPost->zUser)" do not require moderation.
  @ </label>
  @ <input type="hidden" name="trustuser" value="%h(pPost->zUser)">
}

/*

































** Display all posts in a forum thread in chronological order
*/
static void forum_display_chronological(int froot, int target){
  ForumThread *pThread = forumthread_create(froot, 0);
  ForumEntry *p;
  int notAnon = login_is_individual();

  for(p=pThread->pFirst; p; p=p->pNext){
    char *zDate;
    Manifest *pPost;
    int isPrivate;        /* True for posts awaiting moderation */
    int sameUser;         /* True if author is also the reader */




    pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0);
    if( pPost==0 ) continue;
    if( p->fpid==target ){
      @ <div id="forum%d(p->fpid)" class="forumTime forumSel">
    }else if( p->pLeaf!=0 ){
      @ <div id="forum%d(p->fpid)" class="forumTime forumObs">
    }else{
      @ <div id="forum%d(p->fpid)" class="forumTime">
    }
    if( pPost->zThreadTitle ){
      @ <h1>%h(pPost->zThreadTitle)</h1>
    }
    zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
    @ <p>(%d(p->sid)) By %h(pPost->zUser) on %h(zDate)



    fossil_free(zDate);
    if( p->pEdit ){
      @ edit of %z(href("%R/forumpost/%S?t=c",p->pEdit->zUuid))\
      @ %d(p->pEdit->sid)</a>
    }
    if( g.perm.Debug ){
      @ <span class="debug">\
      @ <a href="%R/artifact/%h(p->zUuid)">(artifact)</a></span>
    }
    if( p->firt ){
      ForumEntry *pIrt = p->pPrev;
      while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev;
      if( pIrt ){
        @ in reply to %z(href("%R/forumpost/%S?t=c",pIrt->zUuid))\


























































































































        @ %d(pIrt->sid)</a>
      }
    }
    if( p->pLeaf ){
      @ updated by %z(href("%R/forumpost/%S?t=c",p->pLeaf->zUuid))\
      @ %d(p->pLeaf->sid)</a>
    }
    if( p->fpid!=target ){
      @ %z(href("%R/forumpost/%S?t=c",p->zUuid))[link]</a>
    }
    isPrivate = content_is_private(p->fpid);
    sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0;

    if( isPrivate && !g.perm.ModForum && !sameUser ){
      @ <p><span class="modpending">Awaiting Moderator Approval</span></p>
    }else{
      forum_render(0, pPost->zMimetype, pPost->zWiki, 0);

    }
    if( g.perm.WrForum && p->pLeaf==0 ){
      int sameUser = login_is_individual()
                     && fossil_strcmp(pPost->zUser, g.zLogin)==0;
      @ <p><form action="%R/forumedit" method="POST">
      @ <input type="hidden" name="fpid" value="%s(p->zUuid)">
      if( !isPrivate ){









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


|



>





>
>
>














|
>
>
>


|




|





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



|
|
<
<
|
|



>



|
>







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
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581


582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  @ <br>
  @ <label><input type="checkbox" name="trust">
  @ Trust user "%h(pPost->zUser)"
  @ so that future posts by "%h(pPost->zUser)" do not require moderation.
  @ </label>
  @ <input type="hidden" name="trustuser" value="%h(pPost->zUser)">
}

/*
** Compute a display name from a login name.
**
** If the input login is found in the USER table, then check the USER.INFO
** field to see if it has display-name followed by an email address.
** If it does, that becomes the new display name.  If not, let the display
** name just be the login.
**
** Space to hold the returned name is obtained from fossil_strdup() or
** mprintf() and should be freed by the caller.
*/
char *display_name_from_login(const char *zLogin){
  static Stmt q;
  char *zResult;
  db_static_prepare(&q,
     "SELECT display_name(info) FROM user WHERE login=$login"
  );
  db_bind_text(&q, "$login", zLogin);
  if( db_step(&q)==SQLITE_ROW && db_column_type(&q,0)==SQLITE_TEXT ){
    const char *zDisplay = db_column_text(&q,0);
    if( fossil_strcmp(zDisplay,zLogin)==0 ){
      zResult = fossil_strdup(zLogin);
    }else{
      zResult = mprintf("%s (%s)", zDisplay, zLogin);
    }
  }else{
    zResult = fossil_strdup(zLogin);
  }
  db_reset(&q);
  return zResult;
}


/*
** Display all posts in a forum thread in chronological order
*/
static void forum_display_chronological(int froot, int target, int bRawMode){
  ForumThread *pThread = forumthread_create(froot, 0);
  ForumEntry *p;
  int notAnon = login_is_individual();
  char cMode = bRawMode ? 'r' : 'c';
  for(p=pThread->pFirst; p; p=p->pNext){
    char *zDate;
    Manifest *pPost;
    int isPrivate;        /* True for posts awaiting moderation */
    int sameUser;         /* True if author is also the reader */
    const char *zUuid;
    char *zDisplayName;   /* The display name */
    int sid;

    pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0);
    if( pPost==0 ) continue;
    if( p->fpid==target ){
      @ <div id="forum%d(p->fpid)" class="forumTime forumSel">
    }else if( p->pLeaf!=0 ){
      @ <div id="forum%d(p->fpid)" class="forumTime forumObs">
    }else{
      @ <div id="forum%d(p->fpid)" class="forumTime">
    }
    if( pPost->zThreadTitle ){
      @ <h1>%h(pPost->zThreadTitle)</h1>
    }
    zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
    zDisplayName = display_name_from_login(pPost->zUser);
    sid = p->pEdit ? p->pEdit->sid : p->sid;
    @ <h3 class='forumPostHdr'>(%d(sid)) By %h(zDisplayName) on %h(zDate)
    fossil_free(zDisplayName);
    fossil_free(zDate);
    if( p->pEdit ){
      @ edit of %z(href("%R/forumpost/%S?t=%c",p->pEdit->zUuid,cMode))\
      @ %d(p->pEdit->sid)</a>
    }
    if( g.perm.Debug ){
      @ <span class="debug">\
      @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span>
    }
    if( p->firt ){
      ForumEntry *pIrt = p->pPrev;
      while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev;
      if( pIrt ){
        @ in reply to %z(href("%R/forumpost/%S?t=%c",pIrt->zUuid,cMode))\
        @ %d(pIrt->sid)</a>
      }
    }
    zUuid = p->zUuid;
    if( p->pLeaf ){
      @ updated by %z(href("%R/forumpost/%S?t=%c",p->pLeaf->zUuid,cMode))\
      @ %d(p->pLeaf->sid)</a>
      zUuid = p->pLeaf->zUuid;
    }
    if( p->fpid!=target ){
      @ %z(href("%R/forumpost/%S?t=%c",zUuid,cMode))[link]</a>
    }
    if( !bRawMode ){
      @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a>
    }
    isPrivate = content_is_private(p->fpid);
    sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0;
    @ </h3>
    if( isPrivate && !g.perm.ModForum && !sameUser ){
      @ <p><span class="modpending">Awaiting Moderator Approval</span></p>
    }else{
      const char *zMimetype;
      if( bRawMode ){
        zMimetype = "text/plain";
      }else if( p->pLeaf!=0 ){
        zMimetype = "text/plain";
      }else{
        zMimetype = pPost->zMimetype;
      }
      forum_render(0, zMimetype, pPost->zWiki, 0, 1);
    }
    if( g.perm.WrForum && p->pLeaf==0 ){
      int sameUser = login_is_individual()
                     && fossil_strcmp(pPost->zUser, g.zLogin)==0;
      @ <p><form action="%R/forumedit" method="POST">
      @ <input type="hidden" name="fpid" value="%s(p->zUuid)">
      if( !isPrivate ){
        /* Reply and Edit are only available if the post has already
        ** been approved */
        @ <input type="submit" name="reply" value="Reply">
        if( g.perm.Admin || sameUser ){
          @ <input type="submit" name="edit" value="Edit">
          @ <input type="submit" name="nullout" value="Delete">
        }
      }else if( g.perm.ModForum ){
        /* Provide moderators with moderation buttons for posts that
        ** are pending moderation */
        @ <input type="submit" name="approve" value="Approve">
        @ <input type="submit" name="reject" value="Reject">
        generateTrustControls(pPost);
      }else if( sameUser ){
        /* A post that is pending moderation can be deleted by the
        ** person who originally submitted the post */
        @ <input type="submit" name="reject" value="Delete">
      }
      @ </form></p>
    }
    manifest_destroy(pPost);
    @ </div>
  }

  /* Undocumented "threadtable" query parameter causes thread table
  ** to be displayed for debugging purposes.
  */
  if( PB("threadtable") ){
    @ <hr>
    @ <table border="1" cellpadding="3" cellspacing="0">
    @ <tr><th>sid<th>fpid<th>firt<th>fprev<th>mfirt<th>pLeaf<th>nReply<th>hash
    for(p=pThread->pFirst; p; p=p->pNext){
      @ <tr><td>%d(p->sid)<td>%d(p->fpid)<td>%d(p->firt)\
      @ <td>%d(p->fprev)<td>%d(p->mfirt)\
      @ <td>%d(p->pLeaf?p->pLeaf->fpid:0)<td>%d(p->nReply)\
      @ <td>%S(p->zUuid)</tr>
    }
    @ </table>
  }

  forumthread_delete(pThread);
}
/*
** Display all the edit history of post "target".
*/
static void forum_display_history(int froot, int target, int bRawMode){
  ForumThread *pThread = forumthread_create(froot, 0);
  ForumEntry *p;
  int notAnon = login_is_individual();
  char cMode = bRawMode ? 'r' : 'c';
  ForumEntry *pLeaf = 0;
  int cnt = 0;
  for(p=pThread->pFirst; p; p=p->pNext){
    if( p->fpid==target ){
      pLeaf = p->pLeaf ? p->pLeaf : p;
      break;
    }
  }
  for(p=pThread->pFirst; p; p=p->pNext){
    char *zDate;
    Manifest *pPost;
    int isPrivate;        /* True for posts awaiting moderation */
    int sameUser;         /* True if author is also the reader */
    const char *zUuid;
    char *zDisplayName;   /* The display name */

    if( p->fpid!=pLeaf->fpid && p->pLeaf!=pLeaf ) continue;
    cnt++;
    pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0);
    if( pPost==0 ) continue;
    @ <div id="forum%d(p->fpid)" class="forumTime">
    zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
    zDisplayName = display_name_from_login(pPost->zUser);
    @ <h3 class='forumPostHdr'>(%d(p->sid)) By %h(zDisplayName) on %h(zDate)
    fossil_free(zDisplayName);
    fossil_free(zDate);
    if( g.perm.Debug ){
      @ <span class="debug">\
      @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span>
    }
    if( p->firt && cnt==1 ){
      ForumEntry *pIrt = p->pPrev;
      while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev;
      if( pIrt ){
        @ in reply to %z(href("%R/forumpost/%S?t=%c",pIrt->zUuid,cMode))\
        @ %d(pIrt->sid)</a>
      }
    }
    zUuid = p->zUuid;
    @ %z(href("%R/forumpost/%S?t=c",zUuid))[link]</a>


    if( !bRawMode ){
      @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a>
    }
    isPrivate = content_is_private(p->fpid);
    sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0;
    @ </h3>
    if( isPrivate && !g.perm.ModForum && !sameUser ){
      @ <p><span class="modpending">Awaiting Moderator Approval</span></p>
    }else{
      forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki,
                   0, 1);
    }
    if( g.perm.WrForum && p->pLeaf==0 ){
      int sameUser = login_is_individual()
                     && fossil_strcmp(pPost->zUser, g.zLogin)==0;
      @ <p><form action="%R/forumedit" method="POST">
      @ <input type="hidden" name="fpid" value="%s(p->zUuid)">
      if( !isPrivate ){
419
420
421
422
423
424
425

426
427
428
429
430
431
432
  }
  while( iIndentScale>1 && iIndentScale*pThread->mxIndent>25 ){
    iIndentScale--;
  }
  for(p=pThread->pDisplay; p; p=p->pDisplay){
    int isPrivate;         /* True for posts awaiting moderation */
    int sameUser;          /* True if reader is also the poster */

    pOPost = manifest_get(p->fpid, CFTYPE_FORUM, 0);
    if( p->pLeaf ){
      fpid = p->pLeaf->fpid;
      zUuid = p->pLeaf->zUuid;
      pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
    }else{
      fpid = p->fpid;







>







647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
  }
  while( iIndentScale>1 && iIndentScale*pThread->mxIndent>25 ){
    iIndentScale--;
  }
  for(p=pThread->pDisplay; p; p=p->pDisplay){
    int isPrivate;         /* True for posts awaiting moderation */
    int sameUser;          /* True if reader is also the poster */
    char *zDisplayName;    /* User name to be displayed */
    pOPost = manifest_get(p->fpid, CFTYPE_FORUM, 0);
    if( p->pLeaf ){
      fpid = p->pLeaf->fpid;
      zUuid = p->pLeaf->zUuid;
      pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
    }else{
      fpid = p->fpid;
442
443
444
445
446
447
448


449

450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465

466

467
468
469
470
471

472
473
474
475
476
477
478
479

480
481
482
483
484
485
486
487
488
489
490
491
492
    }
    pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
    if( pPost==0 ) continue;
    if( pPost->zThreadTitle ){
      @ <h1>%h(pPost->zThreadTitle)</h1>
    }
    zDate = db_text(0, "SELECT datetime(%.17g)", pOPost->rDate);


    @ <p>(%d(p->pLeaf?p->pLeaf->sid:p->sid)) By %h(pOPost->zUser) on %h(zDate)

    fossil_free(zDate);
    if( g.perm.Debug ){
      @ <span class="debug">\
      @ <a href="%R/artifact/%h(p->zUuid)">(artifact)</a></span>
    }
    if( p->pLeaf ){
      zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
      if( fossil_strcmp(pOPost->zUser,pPost->zUser)==0 ){
        @ and edited on %h(zDate)
      }else{
        @ as edited by %h(pPost->zUser) on %h(zDate)
      }
      fossil_free(zDate);
      if( g.perm.Debug ){
        @ <span class="debug">\
        @ <a href="%R/artifact/%h(p->pLeaf->zUuid)">(artifact)</a></span>

      }

      manifest_destroy(pOPost);
    }
    if( fpid!=target ){
      @ %z(href("%R/forumpost/%S",zUuid))[link]</a>
    }

    if( p->firt ){
      ForumEntry *pIrt = p->pPrev;
      while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev;
      if( pIrt ){
        @ in reply to %z(href("%R/forumpost/%S?t=h",pIrt->zUuid))\
        @ %d(pIrt->sid)</a>
      }
    }

    isPrivate = content_is_private(fpid);
    sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0;
    if( isPrivate && !g.perm.ModForum && !sameUser ){
      @ <p><span class="modpending">Awaiting Moderator Approval</span></p>
    }else{
      forum_render(0, pPost->zMimetype, pPost->zWiki, 0);
    }
    if( g.perm.WrForum ){
      @ <p><form action="%R/forumedit" method="POST">
      @ <input type="hidden" name="fpid" value="%s(zUuid)">
      if( !isPrivate ){
        /* Reply and Edit are only available if the post has already
        ** been approved */







>
>
|
>



|











|
>

>





>


|





>





|







671
672
673
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
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
    }
    pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
    if( pPost==0 ) continue;
    if( pPost->zThreadTitle ){
      @ <h1>%h(pPost->zThreadTitle)</h1>
    }
    zDate = db_text(0, "SELECT datetime(%.17g)", pOPost->rDate);
    zDisplayName = display_name_from_login(pOPost->zUser);
    @ <h3 class='forumPostHdr'>\
    @ (%d(p->sid)) By %h(zDisplayName) on %h(zDate)
    fossil_free(zDisplayName);
    fossil_free(zDate);
    if( g.perm.Debug ){
      @ <span class="debug">\
      @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span>
    }
    if( p->pLeaf ){
      zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
      if( fossil_strcmp(pOPost->zUser,pPost->zUser)==0 ){
        @ and edited on %h(zDate)
      }else{
        @ as edited by %h(pPost->zUser) on %h(zDate)
      }
      fossil_free(zDate);
      if( g.perm.Debug ){
        @ <span class="debug">\
        @ <a href="%R/artifact/%h(p->pLeaf->zUuid)">\
        @ (artifact-%d(p->pLeaf->fpid))</a></span>
      }
      @ %z(href("%R/forumpost/%S?t=y",p->zUuid))[history]</a>
      manifest_destroy(pOPost);
    }
    if( fpid!=target ){
      @ %z(href("%R/forumpost/%S",zUuid))[link]</a>
    }
    @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a>
    if( p->firt ){
      ForumEntry *pIrt = p->pPrev;
      while( pIrt && pIrt->fpid!=p->mfirt ) pIrt = pIrt->pPrev;
      if( pIrt ){
        @ in reply to %z(href("%R/forumpost/%S?t=h",pIrt->zUuid))\
        @ %d(pIrt->sid)</a>
      }
    }
    @ </h3>
    isPrivate = content_is_private(fpid);
    sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0;
    if( isPrivate && !g.perm.ModForum && !sameUser ){
      @ <p><span class="modpending">Awaiting Moderator Approval</span></p>
    }else{
      forum_render(0, pPost->zMimetype, pPost->zWiki, 0, 1);
    }
    if( g.perm.WrForum ){
      @ <p><form action="%R/forumedit" method="POST">
      @ <input type="hidden" name="fpid" value="%s(zUuid)">
      if( !isPrivate ){
        /* Reply and Edit are only available if the post has already
        ** been approved */
522
523
524
525
526
527
528
529

530





531
532
533
534




















535
536
537
538
539
540
541
542
543
544
545
546

547




548
549
550
551
552
553

554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579



















580

581








582
583

584
585
586
587
588
589
590
591
592
593
594
595
596
597
598









599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618

619
620



621
622
623
624
625
626
627
** it's entire thread.  The selected posting is enclosed within
** <div class='forumSel'>...</div>.  Javascript is used to move the
** selected posting into view after the page loads.
**
** Query parameters:
**
**   name=X        REQUIRED.  The hash of the post to display
**   t=MODE        Display mode. MODE is 'c' for chronological or

**                   'h' for hierarchical, or 'a' for automatic.





*/
void forumpost_page(void){
  forumthread_page();
}





















/*
** WEBPAGE: forumthread
**
** Show all forum messages associated with a particular message thread.
** The result is basically the same as /forumpost except that none of
** the postings in the thread are selected.
**
** Query parameters:
**
**   name=X        REQUIRED.  The hash of any post of the thread.
**   t=MODE        Display mode. MODE is 'c' for chronological or

**                   'h' for hierarchical, or 'a' for automatic.




*/
void forumthread_page(void){
  int fpid;
  int froot;
  const char *zName = P("name");
  const char *zMode = PD("t","a");

  login_check_credentials();
  if( !g.perm.RdForum ){
    login_needed(g.anon.RdForum);
    return;
  }
  if( zName==0 ){
    webpage_error("Missing \"name=\" query parameter");
  }
  fpid = symbolic_name_to_rid(zName, "f");
  if( fpid<=0 ){
    webpage_error("Unknown or ambiguous forum id: \"%s\"", zName);
  }
  style_header("Forum");
  froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
  if( froot==0 ){
    webpage_error("Not a forum post: \"%s\"", zName);
  }
  if( fossil_strcmp(g.zPath,"forumthread")==0 ) fpid = 0;
  if( zMode[0]=='a' ){
    if( cgi_from_mobile() ){
      zMode = "c";  /* Default to chronological on mobile */
    }else{
      zMode = "h";
    }
  }
  if( zMode[0]=='c' ){



















    style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName);

    forum_display_chronological(froot, fpid);








  }else{
    style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);

    forum_display_hierarchical(froot, fpid);
  }
  style_load_js("forum.js");
  style_footer();
}

/*
** Return true if a forum post should be moderated.
*/
static int forum_need_moderation(void){
  if( P("domod") ) return 1;
  if( g.perm.WrTForum ) return 0;
  if( g.perm.ModForum ) return 0;
  return 1;
}










/*
** Add a new Forum Post artifact to the repository.
**
** Return true if a redirect occurs.
*/
static int forum_post(
  const char *zTitle,          /* Title.  NULL for replies */
  int iInReplyTo,              /* Post replying to.  0 for new threads */
  int iEdit,                   /* Post being edited, or zero for a new post */
  const char *zUser,           /* Username.  NULL means use login name */
  const char *zMimetype,       /* Mimetype of content. */
  const char *zContent         /* Content */
){
  char *zDate;
  char *zI;
  char *zG;
  int iBasis;
  Blob x, cksum, formatCheck, errMsg;
  Manifest *pPost;


  schema_forum();



  if( iInReplyTo==0 && iEdit>0 ){
    iBasis = iEdit;
    iInReplyTo = db_int(0, "SELECT firt FROM forumpost WHERE fpid=%d", iEdit);
  }else{
    iBasis = iInReplyTo;
  }
  webpage_assert( (zTitle==0)+(iInReplyTo==0)==1 );







|
>
|
>
>
>
>
>




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











|
>
|
>
>
>
>






>












<












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

>
|
>
>
>
>
>
>
>
>


>















>
>
>
>
>
>
>
>
>




















>


>
>
>







758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833

834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
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
931
932
933
934
935
936
** it's entire thread.  The selected posting is enclosed within
** <div class='forumSel'>...</div>.  Javascript is used to move the
** selected posting into view after the page loads.
**
** Query parameters:
**
**   name=X        REQUIRED.  The hash of the post to display
**   t=MODE        Display mode.
**                   'c' for chronological
**                   'h' for hierarchical
**                   'a' for automatic
**                   'r' for raw
**                   'y' for history of post X only
**   raw           If present, show only the post specified and
**                 show its original unformatted source text.
*/
void forumpost_page(void){
  forumthread_page();
}

/*
** Add an appropriate style_header() to include title of the
** given forum post.
*/
static int forumthread_page_header(int froot, int fpid){
  char *zThreadTitle = 0;

  zThreadTitle = db_text("",
    "SELECT"
    " substr(event.comment,instr(event.comment,':')+2)"
    " FROM forumpost, event"
    " WHERE event.objid=forumpost.fpid"
    "   AND forumpost.fpid=%d;",
    fpid
  );
  style_header("%s%s", zThreadTitle, zThreadTitle[0] ? "" : "Forum");
  fossil_free(zThreadTitle);
  return 0;
}

/*
** WEBPAGE: forumthread
**
** Show all forum messages associated with a particular message thread.
** The result is basically the same as /forumpost except that none of
** the postings in the thread are selected.
**
** Query parameters:
**
**   name=X        REQUIRED.  The hash of any post of the thread.
**   t=MODE        Display mode. MODE is...
**                   'c' for chronological, or
**                   'h' for hierarchical, or
**                   'a' for automatic, or
**                   'r' for raw.
**   raw           Show only the post given by name= and show it unformatted
**   hist          Show only the edit history for the name= post
*/
void forumthread_page(void){
  int fpid;
  int froot;
  const char *zName = P("name");
  const char *zMode = PD("t","a");
  int bRaw = PB("raw");
  login_check_credentials();
  if( !g.perm.RdForum ){
    login_needed(g.anon.RdForum);
    return;
  }
  if( zName==0 ){
    webpage_error("Missing \"name=\" query parameter");
  }
  fpid = symbolic_name_to_rid(zName, "f");
  if( fpid<=0 ){
    webpage_error("Unknown or ambiguous forum id: \"%s\"", zName);
  }

  froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
  if( froot==0 ){
    webpage_error("Not a forum post: \"%s\"", zName);
  }
  if( fossil_strcmp(g.zPath,"forumthread")==0 ) fpid = 0;
  if( zMode[0]=='a' ){
    if( cgi_from_mobile() ){
      zMode = "c";  /* Default to chronological on mobile */
    }else{
      zMode = "h";
    }
  }
  if( zMode[0]!='y' ){
    forumthread_page_header(froot, fpid);
  }
  if( bRaw && fpid ){
    Manifest *pPost;
    pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
    if( pPost==0 ){
      @ <p>No such forum post: %h(zName)
    }else{
      int isPrivate = content_is_private(fpid);
      int notAnon = login_is_individual();
      int sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0;
      if( isPrivate && !g.perm.ModForum && !sameUser ){
        @ <p><span class="modpending">Awaiting Moderator Approval</span></p>
      }else{
        forum_render(0, "text/plain", pPost->zWiki, 0, 0);
      }
      manifest_destroy(pPost);
    }
  }else if( zMode[0]=='c' ){
    style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName);
    style_submenu_element("Unformatted", "%R/%s/%s?t=r", g.zPath, zName);
    forum_display_chronological(froot, fpid, 0);
  }else if( zMode[0]=='r' ){
    style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
    style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName);
    forum_display_chronological(froot, fpid, 1);
  }else if( zMode[0]=='y' ){
    style_header("Edit History Of A Forum Post");
    style_submenu_element("Complete Thread", "%R/%s/%s?t=a", g.zPath, zName);
    forum_display_history(froot, fpid, 1);
  }else{
    style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
    style_submenu_element("Unformatted", "%R/%s/%s?t=r", g.zPath, zName);
    forum_display_hierarchical(froot, fpid);
  }
  style_load_js("forum.js");
  style_footer();
}

/*
** Return true if a forum post should be moderated.
*/
static int forum_need_moderation(void){
  if( P("domod") ) return 1;
  if( g.perm.WrTForum ) return 0;
  if( g.perm.ModForum ) return 0;
  return 1;
}

/*
** Return true if the string is white-space only.
*/
static int whitespace_only(const char *z){
  if( z==0 ) return 1;
  while( z[0] && fossil_isspace(z[0]) ){ z++; }
  return z[0]==0;
}

/*
** Add a new Forum Post artifact to the repository.
**
** Return true if a redirect occurs.
*/
static int forum_post(
  const char *zTitle,          /* Title.  NULL for replies */
  int iInReplyTo,              /* Post replying to.  0 for new threads */
  int iEdit,                   /* Post being edited, or zero for a new post */
  const char *zUser,           /* Username.  NULL means use login name */
  const char *zMimetype,       /* Mimetype of content. */
  const char *zContent         /* Content */
){
  char *zDate;
  char *zI;
  char *zG;
  int iBasis;
  Blob x, cksum, formatCheck, errMsg;
  Manifest *pPost;
  int nContent = zContent ? (int)strlen(zContent) : 0;

  schema_forum();
  if( iEdit==0 && whitespace_only(zContent) ){
    return 0;
  }
  if( iInReplyTo==0 && iEdit>0 ){
    iBasis = iEdit;
    iInReplyTo = db_int(0, "SELECT firt FROM forumpost WHERE fpid=%d", iEdit);
  }else{
    iBasis = iInReplyTo;
  }
  webpage_assert( (zTitle==0)+(iInReplyTo==0)==1 );
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
    if( login_is_nobody() ){
      zUser = "anonymous";
    }else{
      zUser = login_name();
    }
  }
  blob_appendf(&x, "U %F\n", zUser);
  blob_appendf(&x, "W %d\n%s\n", strlen(zContent), zContent);
  md5sum_blob(&x, &cksum);
  blob_appendf(&x, "Z %b\n", &cksum);
  blob_reset(&cksum);

  /* Verify that the artifact we are creating is well-formed */
  blob_init(&formatCheck, 0, 0);
  blob_init(&errMsg, 0, 0);







|







967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
    if( login_is_nobody() ){
      zUser = "anonymous";
    }else{
      zUser = login_name();
    }
  }
  blob_appendf(&x, "U %F\n", zUser);
  blob_appendf(&x, "W %d\n%s\n", nContent, zContent);
  md5sum_blob(&x, &cksum);
  blob_appendf(&x, "Z %b\n", &cksum);
  blob_reset(&cksum);

  /* Verify that the artifact we are creating is well-formed */
  blob_init(&formatCheck, 0, 0);
  blob_init(&errMsg, 0, 0);
697
698
699
700
701
702
703
704

705
706
707
708
709
710
711
*/
static void forum_entry_widget(
  const char *zTitle,
  const char *zMimetype,
  const char *zContent
){
  if( zTitle ){
    @ Title: <input type="input" name="title" value="%h(zTitle)" size="50"><br>

  }
  @ %z(href("%R/markup_help"))Markup style</a>:
  mimetype_option_menu(zMimetype);
  @ <br><textarea name="content" class="wikiedit" cols="80" \
  @ rows="25" wrap="virtual">%h(zContent)</textarea><br>
}








|
>







1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
*/
static void forum_entry_widget(
  const char *zTitle,
  const char *zMimetype,
  const char *zContent
){
  if( zTitle ){
    @ Title: <input type="input" name="title" value="%h(zTitle)" size="50"
    @ maxlength="125"><br>
  }
  @ %z(href("%R/markup_help"))Markup style</a>:
  mimetype_option_menu(zMimetype);
  @ <br><textarea name="content" class="wikiedit" cols="80" \
  @ rows="25" wrap="virtual">%h(zContent)</textarea><br>
}

788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
  const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
  const char *zContent = PDT("content","");
  login_check_credentials();
  if( !g.perm.WrForum ){
    login_needed(g.anon.WrForum);
    return;
  }
  if( P("submit") ){
    if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return;
  }
  if( P("preview") ){
    @ <h1>Preview:</h1>
    forum_render(zTitle, zMimetype, zContent, "forumEdit");
  }
  style_header("New Forum Thread");
  @ <form action="%R/forume1" method="POST">
  @ <h1>New Thread:</h1>
  forum_from_line();
  forum_entry_widget(zTitle, zMimetype, zContent);
  @ <input type="submit" name="preview" value="Preview">
  if( P("preview") ){
    @ <input type="submit" name="submit" value="Submit">
  }else{
    @ <input type="submit" name="submit" value="Submit" disabled>
  }
  if( g.perm.Debug ){
    /* For the test-forumnew page add these extra debugging controls */
    @ <div class="debug">







|


|

|







|







1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
  const char *zContent = PDT("content","");
  login_check_credentials();
  if( !g.perm.WrForum ){
    login_needed(g.anon.WrForum);
    return;
  }
  if( P("submit") && cgi_csrf_safe(1) ){
    if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return;
  }
  if( P("preview") && !whitespace_only(zContent) ){
    @ <h1>Preview:</h1>
    forum_render(zTitle, zMimetype, zContent, "forumEdit", 1);
  }
  style_header("New Forum Thread");
  @ <form action="%R/forume1" method="POST">
  @ <h1>New Thread:</h1>
  forum_from_line();
  forum_entry_widget(zTitle, zMimetype, zContent);
  @ <input type="submit" name="preview" value="Preview">
  if( P("preview") && !whitespace_only(zContent) ){
    @ <input type="submit" name="submit" value="Submit">
  }else{
    @ <input type="submit" name="submit" value="Submit" disabled>
  }
  if( g.perm.Debug ){
    /* For the test-forumnew page add these extra debugging controls */
    @ <div class="debug">
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
    cgi_redirectf("%R/forumpost/%S",P("fpid"));
    return;
  }
  isCsrfSafe = cgi_csrf_safe(1);
  if( g.perm.ModForum && isCsrfSafe ){
    if( P("approve") ){
      const char *zUserToTrust;
      moderation_approve(fpid);
      if( g.perm.AdminForum
       && PB("trust")
       && (zUserToTrust = P("trustuser"))!=0
      ){
        db_multi_exec("UPDATE user SET cap=cap||'4' "
                      "WHERE login=%Q AND cap NOT GLOB '*4*'",
                      zUserToTrust);







|







1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
    cgi_redirectf("%R/forumpost/%S",P("fpid"));
    return;
  }
  isCsrfSafe = cgi_csrf_safe(1);
  if( g.perm.ModForum && isCsrfSafe ){
    if( P("approve") ){
      const char *zUserToTrust;
      moderation_approve('f', fpid);
      if( g.perm.AdminForum
       && PB("trust")
       && (zUserToTrust = P("trustuser"))!=0
      ){
        db_multi_exec("UPDATE user SET cap=cap||'4' "
                      "WHERE login=%Q AND cap NOT GLOB '*4*'",
                      zUserToTrust);
891
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
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
      }else{
        cgi_redirectf("%R/forum");
      }
      return;
    }
  }
  isDelete = P("nullout")!=0;
  if( P("submit") && isCsrfSafe ){




    int done = 1;
    const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
    const char *zContent = PDT("content","");
    if( P("reply") ){
      done = forum_post(0, fpid, 0, 0, zMimetype, zContent);
    }else if( P("edit") || isDelete ){
      done = forum_post(P("title"), 0, fpid, 0, zMimetype, zContent);
    }else{
      webpage_error("Missing 'reply' query parameter");
    }
    if( done ) return;
  }
  if( isDelete ){
    zMimetype = "text/x-fossil-wiki";
    zContent = "";
    if( pPost->zThreadTitle ) zTitle = "";
    style_header("Delete %s", zTitle ? "Post" : "Reply");
    @ <h1>Original Post:</h1>
    forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
                 "forumEdit");
    @ <h1>Change Into:</h1>
    forum_render(zTitle, zMimetype, zContent,"forumEdit");
    @ <form action="%R/forume2" method="POST">
    @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
    @ <input type="hidden" name="nullout" value="1">
    @ <input type="hidden" name="mimetype" value="%h(zMimetype)">
    @ <input type="hidden" name="content" value="%h(zContent)">
    if( zTitle ){
      @ <input type="hidden" name="title" value="%h(zTitle)">
    }
  }else if( P("edit") ){
    /* Provide an edit to the fpid post */
    zMimetype = P("mimetype");
    zContent = PT("content");
    zTitle = P("title");
    if( zContent==0 ) zContent = fossil_strdup(pPost->zWiki);
    if( zMimetype==0 ) zMimetype = fossil_strdup(pPost->zMimetype);
    if( zTitle==0 && pPost->zThreadTitle!=0 ){
      zTitle = fossil_strdup(pPost->zThreadTitle);
    }
    style_header("Edit %s", zTitle ? "Post" : "Reply");
    @ <h1>Original Post:</h1>
    forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
                 "forumEdit");
    if( P("preview") ){
      @ <h1>Preview of Edited Post:</h1>
      forum_render(zTitle, zMimetype, zContent,"forumEdit");
    }
    @ <h1>Revised Message:</h1>
    @ <form action="%R/forume2" method="POST">
    @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
    @ <input type="hidden" name="edit" value="1">
    forum_from_line();
    forum_entry_widget(zTitle, zMimetype, zContent);
  }else{
    /* Reply */

    zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
    zContent = PDT("content","");
    style_header("Reply");
    @ <h1>Replying To:</h1>
    if( pRootPost->zThreadTitle ){
      @ <h3>%h(pRootPost->zThreadTitle)</h3>
    }

    zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
    @ <p>%h(pPost->zThreadTitle ? "Post" : "Reply") by %h(pPost->zUser) on %h(zDate)


    fossil_free(zDate);
    forum_render(0, pPost->zMimetype, pPost->zWiki, "forumEdit");
    if( P("preview") ){
      @ <h1>Preview:</h1>
      forum_render(0, zMimetype,zContent, "forumEdit");
    }
    @ <h1>Enter Reply:</h1>
    @ <form action="%R/forume2" method="POST">
    @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
    @ <input type="hidden" name="reply" value="1">
    forum_from_line();
    forum_entry_widget(0, zMimetype, zContent);
  }
  if( !isDelete ){
    @ <input type="submit" name="preview" value="Preview">
  }
  @ <input type="submit" name="cancel" value="Cancel">
  if( P("preview") || isDelete ){
    @ <input type="submit" name="submit" value="Submit">
  }
  if( g.perm.Debug ){
    /* For the test-forumnew page add these extra debugging controls */
    @ <div class="debug">
    @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
    @ Dry run</label>
    @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
    @ Require moderator approval</label>
    @ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \
    @ Show query parameters</label>
    @ </div>
  }
  @ </form>
  style_footer();
}

/*

** WEBPAGE: forum
**
** The main page for the forum feature.  Show a list of recent forum
** threads.  Also show a search box at the top if search is enabled,
** and a button for creating a new thread, if enabled.
**
** Query parameters:







|
>
>
>
>


<
















|

|



















|

|

|
|

|







>



<

|

>

|
>
>

|
|
|
|

|










|


















>







1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214

1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271

1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
      }else{
        cgi_redirectf("%R/forum");
      }
      return;
    }
  }
  isDelete = P("nullout")!=0;
  if( P("submit")
   && isCsrfSafe
   && (zContent = PDT("content",""))!=0
   && (!whitespace_only(zContent) || isDelete)
  ){
    int done = 1;
    const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);

    if( P("reply") ){
      done = forum_post(0, fpid, 0, 0, zMimetype, zContent);
    }else if( P("edit") || isDelete ){
      done = forum_post(P("title"), 0, fpid, 0, zMimetype, zContent);
    }else{
      webpage_error("Missing 'reply' query parameter");
    }
    if( done ) return;
  }
  if( isDelete ){
    zMimetype = "text/x-fossil-wiki";
    zContent = "";
    if( pPost->zThreadTitle ) zTitle = "";
    style_header("Delete %s", zTitle ? "Post" : "Reply");
    @ <h1>Original Post:</h1>
    forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
                 "forumEdit", 1);
    @ <h1>Change Into:</h1>
    forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
    @ <form action="%R/forume2" method="POST">
    @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
    @ <input type="hidden" name="nullout" value="1">
    @ <input type="hidden" name="mimetype" value="%h(zMimetype)">
    @ <input type="hidden" name="content" value="%h(zContent)">
    if( zTitle ){
      @ <input type="hidden" name="title" value="%h(zTitle)">
    }
  }else if( P("edit") ){
    /* Provide an edit to the fpid post */
    zMimetype = P("mimetype");
    zContent = PT("content");
    zTitle = P("title");
    if( zContent==0 ) zContent = fossil_strdup(pPost->zWiki);
    if( zMimetype==0 ) zMimetype = fossil_strdup(pPost->zMimetype);
    if( zTitle==0 && pPost->zThreadTitle!=0 ){
      zTitle = fossil_strdup(pPost->zThreadTitle);
    }
    style_header("Edit %s", zTitle ? "Post" : "Reply");
    @ <h2>Original Post:</h2>
    forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
                 "forumEdit", 1);
    if( P("preview") ){
      @ <h2>Preview of Edited Post:</h2>
      forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
    }
    @ <h2>Revised Message:</h2>
    @ <form action="%R/forume2" method="POST">
    @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
    @ <input type="hidden" name="edit" value="1">
    forum_from_line();
    forum_entry_widget(zTitle, zMimetype, zContent);
  }else{
    /* Reply */
    char *zDisplayName;
    zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
    zContent = PDT("content","");
    style_header("Reply");

    if( pRootPost->zThreadTitle ){
      @ <h1>Thread: %h(pRootPost->zThreadTitle)</h1>
    }
    @ <h2>Replying To:</h2>
    zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
    zDisplayName = display_name_from_login(pPost->zUser);
    @ <h3 class='forumPostHdr'>By %h(zDisplayName) on %h(zDate)</h3>
    fossil_free(zDisplayName);
    fossil_free(zDate);
    forum_render(0, pPost->zMimetype, pPost->zWiki, "forumEdit", 1);
    if( P("preview") && !whitespace_only(zContent) ){
      @ <h2>Preview:</h2>
      forum_render(0, zMimetype,zContent, "forumEdit", 1);
    }
    @ <h2>Enter Reply:</h2>
    @ <form action="%R/forume2" method="POST">
    @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
    @ <input type="hidden" name="reply" value="1">
    forum_from_line();
    forum_entry_widget(0, zMimetype, zContent);
  }
  if( !isDelete ){
    @ <input type="submit" name="preview" value="Preview">
  }
  @ <input type="submit" name="cancel" value="Cancel">
  if( (P("preview") && !whitespace_only(zContent)) || isDelete ){
    @ <input type="submit" name="submit" value="Submit">
  }
  if( g.perm.Debug ){
    /* For the test-forumnew page add these extra debugging controls */
    @ <div class="debug">
    @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
    @ Dry run</label>
    @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
    @ Require moderator approval</label>
    @ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \
    @ Show query parameters</label>
    @ </div>
  }
  @ </form>
  style_footer();
}

/*
** WEBPAGE: forummain
** WEBPAGE: forum
**
** The main page for the forum feature.  Show a list of recent forum
** threads.  Also show a search box at the top if search is enabled,
** and a button for creating a new thread, if enabled.
**
** Query parameters:
Changes to src/fshell.c.
55
56
57
58
59
60
61

62
63

64
65
66
67
68
69
70
71
72
73
74
  int nArg;
  int mxArg = 0;
  int n, i;
  char **azArg = 0;
  int fDebug;
  pid_t childPid;
  char *zLine = 0;

  fDebug = find_option("debug", 0, 0)!=0;
  db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0);

  db_close(0);
  sqlite3_shutdown();
  linenoiseSetMultiLine(1);
  while( (free(zLine), zLine = linenoise("fossil> ")) ){
    /* Remember shell history within the current session */
    linenoiseHistoryAdd(zLine);

    /* Parse the line of input */
    n = (int)strlen(zLine);
    for(i=0, nArg=1; i<n; i++){
      while( fossil_isspace(zLine[i]) ){ i++; }







>


>



|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  int nArg;
  int mxArg = 0;
  int n, i;
  char **azArg = 0;
  int fDebug;
  pid_t childPid;
  char *zLine = 0;
  char *zPrompt = 0;
  fDebug = find_option("debug", 0, 0)!=0;
  db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0);
  zPrompt = mprintf("fossil (%z)> ", db_get("project-name","no repo"));
  db_close(0);
  sqlite3_shutdown();
  linenoiseSetMultiLine(1);
  while( (free(zLine), zLine = linenoise(zPrompt)) ){
    /* Remember shell history within the current session */
    linenoiseHistoryAdd(zLine);

    /* Parse the line of input */
    n = (int)strlen(zLine);
    for(i=0, nArg=1; i<n; i++){
      while( fossil_isspace(zLine[i]) ){ i++; }
115
116
117
118
119
120
121

122
123
      exit(0);
    }else{
      /* The parent process */
      int status;
      waitpid(childPid, &status, 0);
    }
  }

#endif
}







>


117
118
119
120
121
122
123
124
125
126
      exit(0);
    }else{
      /* The parent process */
      int status;
      waitpid(childPid, &status, 0);
    }
  }
  free(zPrompt);
#endif
}
Changes to src/fuzz.c.
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
**   fossil-fuzz cases
**
** The default is to fuzz the Fossil-wiki translator.  Use the --fuzztype TYPE
** option to fuzz different aspects of the system.
*/
#include "config.h"
#include "fuzz.h"
#include <stdint.h>

#if LOCAL_INTERFACE
/*
** Type of fuzzing:
*/
#define FUZZ_WIKI       0      /* The Fossil-Wiki formatter */
#define FUZZ_MARKDOWN   1      /* The Markdown formatter */







<







49
50
51
52
53
54
55

56
57
58
59
60
61
62
**   fossil-fuzz cases
**
** The default is to fuzz the Fossil-wiki translator.  Use the --fuzztype TYPE
** option to fuzz different aspects of the system.
*/
#include "config.h"
#include "fuzz.h"


#if LOCAL_INTERFACE
/*
** Type of fuzzing:
*/
#define FUZZ_WIKI       0      /* The Fossil-Wiki formatter */
#define FUZZ_MARKDOWN   1      /* The Markdown formatter */
Changes to src/http.c.
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
** Options:
**
**     --compress                 Use ZLIB compression on the payload
**     --mimetype TYPE            Mimetype of the payload
**     --out FILE                 Store the reply in FILE
**     -v                         Verbose output
*/
void test_wget_command(void){
  const char *zMimetype;
  const char *zInFile;
  const char *zOutFile;
  Blob in, out;
  unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS;

  zMimetype = find_option("mimetype",0,1);







|







482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
** Options:
**
**     --compress                 Use ZLIB compression on the payload
**     --mimetype TYPE            Mimetype of the payload
**     --out FILE                 Store the reply in FILE
**     -v                         Verbose output
*/
void test_httpmsg_command(void){
  const char *zMimetype;
  const char *zInFile;
  const char *zOutFile;
  Blob in, out;
  unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS;

  zMimetype = find_option("mimetype",0,1);
Changes to src/http_ssl.c.
28
29
30
31
32
33
34

35
36
37
38
39
40
41
#include "config.h"

#ifdef FOSSIL_ENABLE_SSL

#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>


#include "http_ssl.h"
#include <assert.h>
#include <sys/types.h>

/*
** There can only be a single OpenSSL IO connection open at a time.







>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "config.h"

#ifdef FOSSIL_ENABLE_SSL

#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509.h>

#include "http_ssl.h"
#include <assert.h>
#include <sys/types.h>

/*
** There can only be a single OpenSSL IO connection open at a time.
182
183
184
185
186
187
188
189

190
191
192
193
194
195
196
  int rc, httpVerMin;
  char *bbuf;
  Blob snd, reply;
  int done=0,end=0;
  blob_zero(&snd);
  blob_appendf(&snd, "CONNECT %s:%d HTTP/1.1\r\n", pUrlData->hostname,
      pUrlData->proxyOrigPort);
  blob_appendf(&snd, "Host: %s:%d\r\n", pUrlData->hostname, pUrlData->proxyOrigPort);

  if( pUrlData->proxyAuth ){
    blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth);
  }
  blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1);
  blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent());
  blob_append(&snd, "\r\n", 2);
  BIO_write(bio, blob_buffer(&snd), blob_size(&snd));







|
>







183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  int rc, httpVerMin;
  char *bbuf;
  Blob snd, reply;
  int done=0,end=0;
  blob_zero(&snd);
  blob_appendf(&snd, "CONNECT %s:%d HTTP/1.1\r\n", pUrlData->hostname,
      pUrlData->proxyOrigPort);
  blob_appendf(&snd, "Host: %s:%d\r\n",
               pUrlData->hostname, pUrlData->proxyOrigPort);
  if( pUrlData->proxyAuth ){
    blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth);
  }
  blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1);
  blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent());
  blob_append(&snd, "\r\n", 2);
  BIO_write(bio, blob_buffer(&snd), blob_size(&snd));
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
  if( pUrlData->useProxy ){
    int rc;
    char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
    BIO *sBio = BIO_new_connect(connStr);
    free(connStr);
    if( BIO_do_connect(sBio)<=0 ){
      ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
            pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));

      ssl_close();
      return 1;
    }
    rc = establish_proxy_tunnel(pUrlData, sBio);
    if( rc<200||rc>299 ){
      ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc);
      return 1;







|
>







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  if( pUrlData->useProxy ){
    int rc;
    char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
    BIO *sBio = BIO_new_connect(connStr);
    free(connStr);
    if( BIO_do_connect(sBio)<=0 ){
      ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
            pUrlData->name, pUrlData->port,
            ERR_reason_error_string(ERR_get_error()));
      ssl_close();
      return 1;
    }
    rc = establish_proxy_tunnel(pUrlData, sBio);
    if( rc<200||rc>299 ){
      ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc);
      return 1;
280
281
282
283
284
285
286
287


288
289
290
291
292
293
294
295
296
297
298
299
300
301

302
303
304
305
306
307
308
    ssl_set_errmsg("SSL: cannot open SSL (%s)",
                    ERR_reason_error_string(ERR_get_error()));
    return 1;
  }
  BIO_get_ssl(iBio, &ssl);

#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
  if( !SSL_set_tlsext_host_name(ssl, (pUrlData->useProxy?pUrlData->hostname:pUrlData->name)) ){


    fossil_warning("WARNING: failed to set server name indication (SNI), "
                  "continuing without it.\n");
  }
#endif

  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

  if( !pUrlData->useProxy ){
    char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
    BIO_set_conn_hostname(iBio, connStr);
    free(connStr);
    if( BIO_do_connect(iBio)<=0 ){
      ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
          pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));

      ssl_close();
      return 1;
    }
  }

  if( BIO_do_handshake(iBio)<=0 ) {
    ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",







|
>
>













|
>







283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
    ssl_set_errmsg("SSL: cannot open SSL (%s)",
                    ERR_reason_error_string(ERR_get_error()));
    return 1;
  }
  BIO_get_ssl(iBio, &ssl);

#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
  if( !SSL_set_tlsext_host_name(ssl, 
           (pUrlData->useProxy?pUrlData->hostname:pUrlData->name))
  ){
    fossil_warning("WARNING: failed to set server name indication (SNI), "
                  "continuing without it.\n");
  }
#endif

  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

  if( !pUrlData->useProxy ){
    char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
    BIO_set_conn_hostname(iBio, connStr);
    free(connStr);
    if( BIO_do_connect(iBio)<=0 ){
      ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
         pUrlData->name, pUrlData->port,
         ERR_reason_error_string(ERR_get_error()));
      ssl_close();
      return 1;
    }
  }

  if( BIO_do_handshake(iBio)<=0 ) {
    ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
385
386
387
388
389
390
391
392

393

394
395
396
397
398
399
400
401
  }

  /* Set the Global.zIpAddr variable to the server we are talking to.
  ** This is used to populate the ipaddr column of the rcvfrom table,
  ** if any files are received from the server.
  */
  {
  /* As soon as libressl implements BIO_ADDR_hostname_string/BIO_get_conn_address.

   * check here for the correct LIBRESSL_VERSION_NUMBER too. For now: disable */

  #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L \
      && !defined(LIBRESSL_VERSION_NUMBER)
    char *ip = BIO_ADDR_hostname_string(BIO_get_conn_address(iBio),1);
    g.zIpAddr = mprintf("%s", ip);
    OPENSSL_free(ip);
#else
    /* IPv4 only code */
    const unsigned char *ip;







|
>
|
>
|







391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  }

  /* Set the Global.zIpAddr variable to the server we are talking to.
  ** This is used to populate the ipaddr column of the rcvfrom table,
  ** if any files are received from the server.
  */
  {
  /* As soon as libressl implements
  ** BIO_ADDR_hostname_string/BIO_get_conn_address.
  ** check here for the correct LIBRESSL_VERSION_NUMBER too. For now: disable
  */
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L \
      && !defined(LIBRESSL_VERSION_NUMBER)
    char *ip = BIO_ADDR_hostname_string(BIO_get_conn_address(iBio),1);
    g.zIpAddr = mprintf("%s", ip);
    OPENSSL_free(ip);
#else
    /* IPv4 only code */
    const unsigned char *ip;
415
416
417
418
419
420
421
422

423
424
425

426
427
428
429
430
431
432
  BIO *mem;
  char *zCert, *zHost;

  mem = BIO_new(BIO_s_mem());
  PEM_write_bio_X509(mem, cert);
  BIO_write(mem, "", 1); /* nul-terminate mem buffer */
  BIO_get_mem_data(mem, &zCert);
  zHost = mprintf("cert:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);

  db_set(zHost, zCert, 1);
  free(zHost);
  zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);

  db_set_int(zHost, trusted, 1);
  free(zHost);
  BIO_free(mem);
}

/*
** Get certificate for pUrlData->urlName from global config.







|
>


|
>







423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  BIO *mem;
  char *zCert, *zHost;

  mem = BIO_new(BIO_s_mem());
  PEM_write_bio_X509(mem, cert);
  BIO_write(mem, "", 1); /* nul-terminate mem buffer */
  BIO_get_mem_data(mem, &zCert);
  zHost = mprintf("cert:%s",
            pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
  db_set(zHost, zCert, 1);
  free(zHost);
  zHost = mprintf("trusted:%s",
                  pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
  db_set_int(zHost, trusted, 1);
  free(zHost);
  BIO_free(mem);
}

/*
** Get certificate for pUrlData->urlName from global config.
496
497
498
499
500
501
502



















    N -= got;
    pContent = (void*)&((char*)pContent)[got];
  }
  return total;
}

#endif /* FOSSIL_ENABLE_SSL */


























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
    N -= got;
    pContent = (void*)&((char*)pContent)[got];
  }
  return total;
}

#endif /* FOSSIL_ENABLE_SSL */

/*
** COMMAND: test-ssl-trust-store
**
** Show the file and directory where OpenSSL looks for certificates
** of trusted CAs.
*/
void test_ssl_info(void){
#if !defined(FOSSIL_ENABLE_SSL)
  fossil_print("SSL disabled in this build\n");
#else
  fossil_print("file:  %-14s  %s\n",
     X509_get_default_cert_file_env(),
     X509_get_default_cert_file());
  fossil_print("dir:   %-14s  %s\n",
     X509_get_default_cert_dir_env(),
     X509_get_default_cert_dir());
#endif
}
Changes to src/import.c.
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
}

/*
** Use data accumulated in gg from a "tag" record to add a new
** control artifact to the BLOB table.
*/
static void finish_tag(void){
  Blob record, cksum;
  if( gg.zDate && gg.zTag && gg.zFrom && gg.zUser ){

    blob_zero(&record);
    blob_appendf(&record, "D %s\n", gg.zDate);
    blob_appendf(&record, "T +sym-%F%F%F %s", gimport.zTagPre, gg.zTag,
        gimport.zTagSuf, gg.zFrom);
    if( gg.zComment ){
      blob_appendf(&record, " %F", gg.zComment);
    }
    blob_appendf(&record, "\nU %F\n", gg.zUser);
    md5sum_blob(&record, &cksum);
    blob_appendf(&record, "Z %b\n", &cksum);
    fast_insert_content(&record, 0, 0, 1);
    blob_reset(&cksum);

  }
  import_reset(0);
}

/*
** Compare two ImportFile objects for sorting
*/







<

>












>







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
}

/*
** Use data accumulated in gg from a "tag" record to add a new
** control artifact to the BLOB table.
*/
static void finish_tag(void){

  if( gg.zDate && gg.zTag && gg.zFrom && gg.zUser ){
    Blob record, cksum;
    blob_zero(&record);
    blob_appendf(&record, "D %s\n", gg.zDate);
    blob_appendf(&record, "T +sym-%F%F%F %s", gimport.zTagPre, gg.zTag,
        gimport.zTagSuf, gg.zFrom);
    if( gg.zComment ){
      blob_appendf(&record, " %F", gg.zComment);
    }
    blob_appendf(&record, "\nU %F\n", gg.zUser);
    md5sum_blob(&record, &cksum);
    blob_appendf(&record, "Z %b\n", &cksum);
    fast_insert_content(&record, 0, 0, 1);
    blob_reset(&cksum);
    blob_reset(&record);
  }
  import_reset(0);
}

/*
** Compare two ImportFile objects for sorting
*/
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
  ** tag or not.  So make an entry in the XTAG table to record this tag
  ** but overwrite that entry if a later instance of the same tag appears.
  **
  ** This behavior seems like a bug in git-fast-export, but it is easier
  ** to work around the problem than to fix git-fast-export.
  */
  if( gg.tagCommit && gg.zDate && gg.zUser && gg.zFrom ){


    blob_appendf(&record, "D %s\n", gg.zDate);
    blob_appendf(&record, "T +sym-%F%F%F %s\n", gimport.zBranchPre, gg.zBranch,
        gimport.zBranchSuf, gg.zPrevCheckin);
    blob_appendf(&record, "U %F\n", gg.zUser);
    md5sum_blob(&record, &cksum);
    blob_appendf(&record, "Z %b\n", &cksum);
    db_multi_exec(
       "INSERT OR REPLACE INTO xtag(tname, tcontent)"
       " VALUES(%Q,%Q)", gg.zBranch, blob_str(&record)
    );
    blob_reset(&record);
    blob_reset(&cksum);
  }


  fossil_free(gg.zPrevBranch);
  gg.zPrevBranch = gg.zBranch;
  gg.zBranch = 0;
  import_reset(0);
}

/*







>
>










<



>







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
  ** tag or not.  So make an entry in the XTAG table to record this tag
  ** but overwrite that entry if a later instance of the same tag appears.
  **
  ** This behavior seems like a bug in git-fast-export, but it is easier
  ** to work around the problem than to fix git-fast-export.
  */
  if( gg.tagCommit && gg.zDate && gg.zUser && gg.zFrom ){
    record.nUsed = 0
      /*in case fast_insert_comment() did not indirectly blob_reset() it */;
    blob_appendf(&record, "D %s\n", gg.zDate);
    blob_appendf(&record, "T +sym-%F%F%F %s\n", gimport.zBranchPre, gg.zBranch,
        gimport.zBranchSuf, gg.zPrevCheckin);
    blob_appendf(&record, "U %F\n", gg.zUser);
    md5sum_blob(&record, &cksum);
    blob_appendf(&record, "Z %b\n", &cksum);
    db_multi_exec(
       "INSERT OR REPLACE INTO xtag(tname, tcontent)"
       " VALUES(%Q,%Q)", gg.zBranch, blob_str(&record)
    );

    blob_reset(&cksum);
  }

  blob_reset(&record);
  fossil_free(gg.zPrevBranch);
  gg.zPrevBranch = gg.zBranch;
  gg.zBranch = 0;
  import_reset(0);
}

/*
1634
1635
1636
1637
1638
1639
1640

1641
1642
1643
1644

1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664

1665
1666
1667
1668
1669
1670
1671
**   -f|--force           overwrite repository if already exists
**   -q|--quiet           omit progress output
**   --no-rebuild         skip the "rebuilding metadata" step
**   --no-vacuum          skip the final VACUUM of the database file
**   --rename-trunk NAME  use NAME as name of imported trunk branch
**   --rename-branch PAT  rename all branch names using PAT pattern
**   --rename-tag PAT     rename all tag names using PAT pattern

**
** The --incremental option allows an existing repository to be extended
** with new content.  The --rename-* options may be useful to avoid name
** conflicts when using the --incremental option.

**
** The argument to --rename-* contains one "%" character to be replaced
** with the original name.  For example, "--rename-tag svn-%-tag" renames
** the tag called "release" to "svn-release-tag".
**
** --ignore-tree is useful for importing Subversion repositories which
** move branches to subdirectories of "branches/deleted" instead of
** deleting them.  It can be supplied multiple times if necessary.
**
** See also: export
*/
void import_cmd(void){
  char *zPassword;
  FILE *pIn;
  Stmt q;
  int forceFlag = find_option("force", "f", 0)!=0;
  int svnFlag = find_option("svn", 0, 0)!=0;
  int gitFlag = find_option("git", 0, 0)!=0;
  int omitRebuild = find_option("no-rebuild",0,0)!=0;
  int omitVacuum = find_option("no-vacuum",0,0)!=0;


  /* Options common to all input formats */
  int incrFlag = find_option("incremental", "i", 0)!=0;

  /* Options for --svn only */
  const char *zBase = "";
  int flatFlag = 0;







>



|
>




















>







1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
**   -f|--force           overwrite repository if already exists
**   -q|--quiet           omit progress output
**   --no-rebuild         skip the "rebuilding metadata" step
**   --no-vacuum          skip the final VACUUM of the database file
**   --rename-trunk NAME  use NAME as name of imported trunk branch
**   --rename-branch PAT  rename all branch names using PAT pattern
**   --rename-tag PAT     rename all tag names using PAT pattern
**   --admin-user|-A NAME use NAME for the admin user 
**
** The --incremental option allows an existing repository to be extended
** with new content.  The --rename-* options may be useful to avoid name
** conflicts when using the --incremental option. The --admin-user
** option is ignored if --incremental is specified.
**
** The argument to --rename-* contains one "%" character to be replaced
** with the original name.  For example, "--rename-tag svn-%-tag" renames
** the tag called "release" to "svn-release-tag".
**
** --ignore-tree is useful for importing Subversion repositories which
** move branches to subdirectories of "branches/deleted" instead of
** deleting them.  It can be supplied multiple times if necessary.
**
** See also: export
*/
void import_cmd(void){
  char *zPassword;
  FILE *pIn;
  Stmt q;
  int forceFlag = find_option("force", "f", 0)!=0;
  int svnFlag = find_option("svn", 0, 0)!=0;
  int gitFlag = find_option("git", 0, 0)!=0;
  int omitRebuild = find_option("no-rebuild",0,0)!=0;
  int omitVacuum = find_option("no-vacuum",0,0)!=0;
  const char *zDefaultUser = find_option("admin-user","A",1);

  /* Options common to all input formats */
  int incrFlag = find_option("incremental", "i", 0)!=0;

  /* Options for --svn only */
  const char *zBase = "";
  int flatFlag = 0;
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
    db_create_repository(g.argv[2]);
  }
  db_open_repository(g.argv[2]);
  db_open_config(0, 0);

  db_begin_transaction();
  if( !incrFlag ){
    db_initial_setup(0, 0, 0);
    db_set("main-branch", gimport.zTrunkName, 0);
  }

  if( svnFlag ){
    db_multi_exec(
       "CREATE TEMP TABLE xrevisions("
       " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0,"







|







1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
    db_create_repository(g.argv[2]);
  }
  db_open_repository(g.argv[2]);
  db_open_config(0, 0);

  db_begin_transaction();
  if( !incrFlag ){
    db_initial_setup(0, 0, zDefaultUser);
    db_set("main-branch", gimport.zTrunkName, 0);
  }

  if( svnFlag ){
    db_multi_exec(
       "CREATE TEMP TABLE xrevisions("
       " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0,"
Changes to src/info.c.
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  zParentCode = db_get("parent-project-code",0);
  if( zParentCode ){
    fossil_print("derived-from: %s %s\n", zParentCode,
                 db_get("parent-project-name",""));
  }
}


/*
** COMMAND: info
**
** Usage: %fossil info ?VERSION | REPOSITORY_FILENAME? ?OPTIONS?
**
** With no arguments, provide information about the current tree.
** If an argument is specified, provide information about the object







<







165
166
167
168
169
170
171

172
173
174
175
176
177
178
  zParentCode = db_get("parent-project-code",0);
  if( zParentCode ){
    fossil_print("derived-from: %s %s\n", zParentCode,
                 db_get("parent-project-name",""));
  }
}


/*
** COMMAND: info
**
** Usage: %fossil info ?VERSION | REPOSITORY_FILENAME? ?OPTIONS?
**
** With no arguments, provide information about the current tree.
** If an argument is specified, provide information about the object
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
    db_record_repository_filename(g.argv[2]);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
    showParentProject();
    extraRepoInfo();
    return;
  }
  db_find_and_open_repository(0,0);
  verify_all_options();
  if( g.argc==2 ){
    int vid;
         /* 012345678901234 */
    db_record_repository_filename(0);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));



    if( g.localOpen ){
      fossil_print("repository:   %s\n", db_repository_filename());
      fossil_print("local-root:   %s\n", g.zLocalRoot);
    }

    if( verboseFlag ) extraRepoInfo();

    if( g.zConfigDbName ){
      fossil_print("config-db:    %s\n", g.zConfigDbName);
    }

    fossil_print("project-code: %s\n", db_get("project-code", ""));
    showParentProject();
    vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
    if( vid ){
      show_common_info(vid, "checkout:", 1, 1);
    }
    fossil_print("check-ins:    %d\n",
             db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));















  }else{
    int rid;
    rid = name_to_rid(g.argv[2]);
    if( rid==0 ){
      fossil_fatal("no such object: %s", g.argv[2]);
    }
    show_common_info(rid, "uuid:", 1, 1);







|



|
|
|
>
>
>




>
|
>



>
|
|
|
|
|
|
|

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







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
    db_record_repository_filename(g.argv[2]);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
    showParentProject();
    extraRepoInfo();
    return;
  }
  db_find_and_open_repository(OPEN_OK_NOT_FOUND,0);
  verify_all_options();
  if( g.argc==2 ){
    int vid;
    if( g.repositoryOpen ){
      db_record_repository_filename(0);
      fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    }else{
      db_open_config(0,1);
    }
    if( g.localOpen ){
      fossil_print("repository:   %s\n", db_repository_filename());
      fossil_print("local-root:   %s\n", g.zLocalRoot);
    }
    if( verboseFlag && g.repositoryOpen ){
      extraRepoInfo();
    }
    if( g.zConfigDbName ){
      fossil_print("config-db:    %s\n", g.zConfigDbName);
    }
    if( g.repositoryOpen ){
      fossil_print("project-code: %s\n", db_get("project-code", ""));
      showParentProject();
      vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
      if( vid ){
        show_common_info(vid, "checkout:", 1, 1);
      }
      fossil_print("check-ins:    %d\n",
             db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));
    }
    if( verboseFlag || !g.repositoryOpen ){
      Blob vx;
      char *z;
      fossil_version_blob(&vx, 0);
      z = strstr(blob_str(&vx), "version");
      if( z ){
        z += 8;
      }else{
        z = blob_str(&vx);
      }
      fossil_print("fossil:       %z\n", file_fullexename(g.nameOfExe));
      fossil_print("version:      %s", z);
      blob_reset(&vx);
    }
  }else{
    int rid;
    rid = name_to_rid(g.argv[2]);
    if( rid==0 ){
      fossil_fatal("no such object: %s", g.argv[2]);
    }
    show_common_info(rid, "uuid:", 1, 1);
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
         |TIMELINE_NOSCROLL
         |TIMELINE_XMERGE
         |TIMELINE_CHPICK,
       0, 0, 0, rid, rid2, 0);
  db_finalize(&q);
}

/*
** Show a graph all wiki, tickets, and check-ins that refer to object zUuid.
**
** If zLabel is not NULL and the graph is not empty, then output zLabel as
** a prefix to the graph.
*/
void render_backlink_graph(const char *zUuid, const char *zLabel){
  Blob sql;
  Stmt q;
  char *zGlob;
  zGlob = mprintf("%.5s*", zUuid);
  db_multi_exec(
     "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
     "DELETE FROM ok;"
     "INSERT OR IGNORE INTO ok"
     " SELECT srcid FROM backlink"
     "  WHERE target GLOB %Q"
     "    AND %Q GLOB (target || '*');",
     zGlob, zUuid
  );
  if( !db_exists("SELECT 1 FROM ok") ) return;
  if( zLabel ) cgi_printf("%s", zLabel);
  blob_zero(&sql);
  blob_append(&sql, timeline_query_for_www(), -1);
  blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
  db_prepare(&q, "%s", blob_sql_text(&sql));
  www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
                     0, 0, 0, 0, 0, 0);
  db_finalize(&q);
}

/*
** WEBPAGE: test-backlinks
**
** Show a timeline of all check-ins and other events that have entries
** in the backlink table.  This is used for testing the rendering
** of the "References" section of the /info page.
*/
void backlink_timeline_page(void){
  Blob sql;
  Stmt q;

  login_check_credentials();
  if( !g.perm.Read || !g.perm.RdTkt || !g.perm.RdWiki ){
    login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
    return;
  }
  style_header("Backlink Timeline (Internal Testing Use)");
  db_multi_exec(
     "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
     "DELETE FROM ok;"
     "INSERT OR IGNORE INTO ok"
     " SELECT blob.rid FROM backlink, blob"
     "  WHERE blob.uuid BETWEEN backlink.target AND (backlink.target||'x')"
  );
  blob_zero(&sql);
  blob_append(&sql, timeline_query_for_www(), -1);
  blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
  db_prepare(&q, "%s", blob_sql_text(&sql));
  www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
                     0, 0, 0, 0, 0, 0);
  db_finalize(&q);
  style_footer();
}


/*
** Append the difference between artifacts to the output
*/
static void append_diff(
  const char *zFrom,    /* Diff from this artifact */
  const char *zTo,      /*  ... to this artifact */







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







320
321
322
323
324
325
326

































































327
328
329
330
331
332
333
         |TIMELINE_NOSCROLL
         |TIMELINE_XMERGE
         |TIMELINE_CHPICK,
       0, 0, 0, rid, rid2, 0);
  db_finalize(&q);
}



































































/*
** Append the difference between artifacts to the output
*/
static void append_diff(
  const char *zFrom,    /* Diff from this artifact */
  const char *zTo,      /*  ... to this artifact */
847
848
849
850
851
852
853
854
855
856


857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
        @ <tr><th>Received&nbsp;From:</th>
        @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate) \
        @ (<a href="%R/rcvfrom?rcvid=%d(rcvid)">Rcvid %d(rcvid)</a>)</td></tr>
      }
      db_finalize(&q2);
    }

    /* Only show links to read wiki pages if the users can read wiki
    ** and if the wiki pages already exist */
    if( g.perm.RdWiki


     && ((okWiki = wiki_tagid2("checkin",zUuid))!=0 ||
                 blob_size(&wiki_read_links)>0)
     && db_get_boolean("wiki-about",1)
    ){
      const char *zLinks = blob_str(&wiki_read_links);
      @ <tr><th>Wiki:</th><td>\
      if( okWiki ){
        @ %z(href("%R/wiki?name=checkin/%s",zUuid))this checkin</a>\
      }else if( zLinks[0] ){
        zLinks += 3;
      }
      @ %s(zLinks)</td></tr>
    }

    /* Only show links to create new wiki pages if the users can write wiki







|

|
>
>





|

|







802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
        @ <tr><th>Received&nbsp;From:</th>
        @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate) \
        @ (<a href="%R/rcvfrom?rcvid=%d(rcvid)">Rcvid %d(rcvid)</a>)</td></tr>
      }
      db_finalize(&q2);
    }

    /* Only show links to edit wiki pages if the users can read wiki
    ** and if the wiki pages already exist */
    if( g.perm.WrWiki
     && g.perm.RdWiki
     && g.perm.Write
     && ((okWiki = wiki_tagid2("checkin",zUuid))!=0 ||
                 blob_size(&wiki_read_links)>0)
     && db_get_boolean("wiki-about",1)
    ){
      const char *zLinks = blob_str(&wiki_read_links);
      @ <tr><th>Edit&nbsp;Wiki:</th><td>\
      if( okWiki ){
        @ %z(href("%R/wikiedit?name=checkin/%s",zUuid))this checkin</a>\
      }else if( zLinks[0] ){
        zLinks += 3;
      }
      @ %s(zLinks)</td></tr>
    }

    /* Only show links to create new wiki pages if the users can write wiki
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
        /*NOTREACHED*/
      }else{
        cgi_redirectf("%R/modreq");
        /*NOTREACHED*/
      }
    }
    if( strcmp(zModAction,"approve")==0 ){
      moderation_approve(rid);
    }
  }
  style_header("Update of \"%h\"", pWiki->zWikiTitle);
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
  style_submenu_element("Raw", "artifact/%s", zUuid);
  style_submenu_element("History", "whistory?name=%t", pWiki->zWikiTitle);







|







977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
        /*NOTREACHED*/
      }else{
        cgi_redirectf("%R/modreq");
        /*NOTREACHED*/
      }
    }
    if( strcmp(zModAction,"approve")==0 ){
      moderation_approve('w', rid);
    }
  }
  style_header("Update of \"%h\"", pWiki->zWikiTitle);
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
  style_submenu_element("Raw", "artifact/%s", zUuid);
  style_submenu_element("History", "whistory?name=%t", pWiki->zWikiTitle);
1880
1881
1882
1883
1884
1885
1886

1887
1888
1889
1890
1891
1892
1893
                          " 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);
}

/*
** Render a hex dump of a file.
*/







>







1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
                          " 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);
  fossil_free(style_csp(1));
  cgi_set_content_type(zMime);
  cgi_set_content(&content);
}

/*
** Render a hex dump of a file.
*/
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
        /*NOTREACHED*/
      }else{
        cgi_redirectf("%R/modreq");
        /*NOTREACHED*/
      }
    }
    if( strcmp(zModAction,"approve")==0 ){
      moderation_approve(rid);
    }
  }
  zTktTitle = db_table_has_column("repository", "ticket", "title" )
      ? db_text("(No title)", 
                "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
      : 0;
  style_header("Ticket Change Details");







|







2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
        /*NOTREACHED*/
      }else{
        cgi_redirectf("%R/modreq");
        /*NOTREACHED*/
      }
    }
    if( strcmp(zModAction,"approve")==0 ){
      moderation_approve('t', rid);
    }
  }
  zTktTitle = db_table_has_column("repository", "ticket", "title" )
      ? db_text("(No title)", 
                "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
      : 0;
  style_header("Ticket Change Details");
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
    @ <input type="submit" value="Submit">
    @ </form>
    @ </blockquote>
  }

  @ <div class="section">Changes</div>
  @ <p>
  ticket_output_change_artifact(pTktChng, 0);
  manifest_destroy(pTktChng);
  style_footer();
}


/*
** WEBPAGE: info







|







2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
    @ <input type="submit" value="Submit">
    @ </form>
    @ </blockquote>
  }

  @ <div class="section">Changes</div>
  @ <p>
  ticket_output_change_artifact(pTktChng, 0, 1);
  manifest_destroy(pTktChng);
  style_footer();
}


/*
** WEBPAGE: info
2509
2510
2511
2512
2513
2514
2515

2516
2517
2518
2519
2520
2521
2522
    ambiguous_page();
    return;
  }
  rc = name_to_uuid(&uuid, -1, "*");
  if( rc==1 ){
    if( validate16(zName, nLen) ){
      if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){

        tktview_page();
        return;
      }
      if( db_exists("SELECT 1 FROM tag"
                    " WHERE tagname GLOB 'event-%q*'", zName) ){
        event_page();
        return;







>







2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
    ambiguous_page();
    return;
  }
  rc = name_to_uuid(&uuid, -1, "*");
  if( rc==1 ){
    if( validate16(zName, nLen) ){
      if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
        cgi_set_parameter_nocopy("tl","1",0);
        tktview_page();
        return;
      }
      if( db_exists("SELECT 1 FROM tag"
                    " WHERE tagname GLOB 'event-%q*'", zName) ){
        event_page();
        return;
Changes to src/json.c.
50
51
52
53
54
55
56
57
58
59
60



61
62
63
64
65
66
67
  "payload" /* payload */,
  "requestId" /*requestId*/,
  "resultCode" /*resultCode*/,
  "resultText" /*resultText*/,
  "timestamp" /*timestamp*/
};



/*
** Returns true (non-0) if fossil appears to be running in JSON mode.



*/
int fossil_has_json(){
  return g.json.isJsonMode && (g.isHTTP || g.json.post.o);
}

/*
** Placeholder /json/XXX page impl for NYI (Not Yet Implemented)







<
<


>
>
>







50
51
52
53
54
55
56


57
58
59
60
61
62
63
64
65
66
67
68
  "payload" /* payload */,
  "requestId" /*requestId*/,
  "resultCode" /*resultCode*/,
  "resultText" /*resultText*/,
  "timestamp" /*timestamp*/
};



/*
** Returns true (non-0) if fossil appears to be running in JSON mode.
** and either has JSON POSTed input awaiting consumption or fossil is
** running in HTTP mode (in which case certain JSON data *might* be
** available via GET parameters).
*/
int fossil_has_json(){
  return g.json.isJsonMode && (g.isHTTP || g.json.post.o);
}

/*
** Placeholder /json/XXX page impl for NYI (Not Yet Implemented)
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
** NULL if no match is found.
**
** ENV means the system environment (getenv()).
**
** Precedence: POST.payload, GET/COOKIE/non-JSON POST, JSON POST, ENV.
**
** FIXME: the precedence SHOULD be: GET, POST.payload, POST, COOKIE,
** ENV, but the amalgamation of the GET/POST vars makes it difficult
** for me to do that. Since fossil only uses one cookie, cookie
** precedence isn't a real/high-priority problem.
*/
cson_value * json_getenv( char const * zKey ){
  cson_value * rc;
  rc = g.json.reqPayload.o
    ? cson_object_get( g.json.reqPayload.o, zKey )
    : NULL;







|
|







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
** NULL if no match is found.
**
** ENV means the system environment (getenv()).
**
** Precedence: POST.payload, GET/COOKIE/non-JSON POST, JSON POST, ENV.
**
** FIXME: the precedence SHOULD be: GET, POST.payload, POST, COOKIE,
** ENV, but the amalgamation of the GET/POST vars makes it effectively
** impossible to do that. Since fossil only uses one cookie, cookie
** precedence isn't a real/high-priority problem.
*/
cson_value * json_getenv( char const * zKey ){
  cson_value * rc;
  rc = g.json.reqPayload.o
    ? cson_object_get( g.json.reqPayload.o, zKey )
    : NULL;
574
575
576
577
578
579
580















581
582
583
584
585
586
587
          : "application/json";
      }else{
        return "text/plain";
      }
    }
  }
}
















/*
** Sends pResponse to the output stream as the response object.  This
** function does no validation of pResponse except to assert() that it
** is not NULL. The caller is responsible for ensuring that it meets
** API response envelope conventions.
**







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







575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
          : "application/json";
      }else{
        return "text/plain";
      }
    }
  }
}

/*
 ** Given a request CONTENT_TYPE value, this function returns true
 ** if it is of a type which the JSON API can ostensibly read.
 **
 ** It accepts any of application/json, text/plain, or
 ** application/javascript. The former is preferred, but was not
 ** widespread when this API was initially built, so the latter forms
 ** are permitted as fallbacks.
 */
int json_can_consume_content_type(const char * zType){
  return fossil_strcmp(zType, "application/json")==0
    || fossil_strcmp(zType,"text/plain")==0/*assume this MIGHT be JSON*/
    || fossil_strcmp(zType,"application/javascript")==0;
}

/*
** Sends pResponse to the output stream as the response object.  This
** function does no validation of pResponse except to assert() that it
** is not NULL. The caller is responsible for ensuring that it meets
** API response envelope conventions.
**
628
629
630
631
632
633
634






635
636
637
638



639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
**
** Must be called once before login_check_credentials() is called or
** we will not be able to replace fossil's internal idea of the auth
** info in time (and future changes to that state may cause unexpected
** results).
**
** The result of this call are cached for future calls.






*/
cson_value * json_auth_token(){
    assert(g.json.gc.a && "json_main_bootstrap() was not called!");
    if( !g.json.authToken ){



    /* Try to get an authorization token from GET parameter, POSTed
       JSON, or fossil cookie (in that order). */
    g.json.authToken = json_getenv(FossilJsonKeys.authToken);
    if(g.json.authToken
       && cson_value_is_string(g.json.authToken)
       && !PD(login_cookie_name(),NULL)){
      /* tell fossil to use this login info.

      FIXME?: because the JSON bits don't carry around
      login_cookie_name(), there is(?) a potential(?) login hijacking
      window here. We may need to change the JSON auth token to be in
      the form: login_cookie_name()=...

      Then again, the hardened cookie value helps ensure that
      only a proper key/value match is valid.
      */
      cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) );
    }else if( g.isHTTP ){
      /* try fossil's conventional cookie. */
      /* Reminder: chicken/egg scenario regarding db access in CLI
         mode because login_cookie_name() needs the db. CLI
         mode does not use any authentication, so we don't need







>
>
>
>
>
>


|
|
>
>
>








|
|
|
|

|
|







644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
**
** Must be called once before login_check_credentials() is called or
** we will not be able to replace fossil's internal idea of the auth
** info in time (and future changes to that state may cause unexpected
** results).
**
** The result of this call are cached for future calls.
**
** Special case: if g.useLocalauth is true (i.e. the --localauth flag
** was used to start the fossil server instance) and the current
** connection is "local", any authToken provided by the user is
** ignored and no new token is created: localauth mode trumps the
** authToken.
*/
cson_value * json_auth_token(){
  assert(g.json.gc.a && "json_main_bootstrap() was not called!");
  if( g.json.authToken==0 && g.noPswd==0
      /* g.noPswd!=0 means the user was logged in via a local
         connection using --localauth. */
      ){
    /* Try to get an authorization token from GET parameter, POSTed
       JSON, or fossil cookie (in that order). */
    g.json.authToken = json_getenv(FossilJsonKeys.authToken);
    if(g.json.authToken
       && cson_value_is_string(g.json.authToken)
       && !PD(login_cookie_name(),NULL)){
      /* tell fossil to use this login info.

         FIXME?: because the JSON bits don't carry around
         login_cookie_name(), there is(?) a potential(?) login hijacking
         window here. We may need to change the JSON auth token to be in
         the form: login_cookie_name()=...

         Then again, the hardened cookie value helps ensure that
         only a proper key/value match is valid.
      */
      cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) );
    }else if( g.isHTTP ){
      /* try fossil's conventional cookie. */
      /* Reminder: chicken/egg scenario regarding db access in CLI
         mode because login_cookie_name() needs the db. CLI
         mode does not use any authentication, so we don't need
914
915
916
917
918
919
920
921

922
923
924
925
926
927
928
  assert(g.json.gc.a && "json_main_bootstrap() was not called!");
  assert( (0==once) && "json_mode_bootstrap() called too many times!");
  if( once ){
    return;
  }else{
    once = 1;
  }
  g.json.isJsonMode = 1;

  g.json.resultCode = 0;
  g.json.cmd.offset = -1;
  g.json.jsonp = PD("jsonp",NULL)
    /* FIXME: do some sanity checking on g.json.jsonp and ignore it
       if it is not halfway reasonable.
    */
    ;







|
>







939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
  assert(g.json.gc.a && "json_main_bootstrap() was not called!");
  assert( (0==once) && "json_mode_bootstrap() called too many times!");
  if( once ){
    return;
  }else{
    once = 1;
  }
  assert(g.json.isJsonMode
         && "g.json.isJsonMode should have been set up by now.");
  g.json.resultCode = 0;
  g.json.cmd.offset = -1;
  g.json.jsonp = PD("jsonp",NULL)
    /* FIXME: do some sanity checking on g.json.jsonp and ignore it
       if it is not halfway reasonable.
    */
    ;
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
      break;
    }
    inFile = (0==strcmp("-",jfile))
      ? stdin
      : fossil_fopen(jfile,"rb");
    if(!inFile){
      g.json.resultCode = FSL_JSON_E_FILE_OPEN_FAILED;
      fossil_panic("Could not open JSON file [%s].",jfile)
        /* Does not return. */
        ;
    }
    cgi_parse_POST_JSON(inFile, 0);
    if( stdin != inFile ){
      fclose(inFile);
    }
    break;
  }

  /* g.json.reqPayload exists only to simplify some of our access to
     the request payload. We currently only use this in the context of
     Object payloads, not Arrays, strings, etc.
  */







|




<
|
<







1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031

1032

1033
1034
1035
1036
1037
1038
1039
      break;
    }
    inFile = (0==strcmp("-",jfile))
      ? stdin
      : fossil_fopen(jfile,"rb");
    if(!inFile){
      g.json.resultCode = FSL_JSON_E_FILE_OPEN_FAILED;
      fossil_fatal("Could not open JSON file [%s].",jfile)
        /* Does not return. */
        ;
    }
    cgi_parse_POST_JSON(inFile, 0);

    fossil_fclose(inFile);

    break;
  }

  /* g.json.reqPayload exists only to simplify some of our access to
     the request payload. We currently only use this in the context of
     Object payloads, not Arrays, strings, etc.
  */
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108

1109
1110
1111
1112
1113
1114
1115
    short i = 0;
#define NEXT cson_string_cstr(          \
                 cson_value_get_string( \
                   cson_array_get(ar,i) \
                   ))
    char const * tok = NEXT;
    while( tok ){
      if( !g.isHTTP/*workaround for "abbreviated name" in CLI mode*/
          ? (0==strcmp(g.argv[1],tok))
          : (0==strncmp("json",tok,4))

          ){
        g.json.cmd.offset = i;
        break;
      }
      ++i;
      tok = NEXT;
    }







|
<
|
>







1123
1124
1125
1126
1127
1128
1129
1130

1131
1132
1133
1134
1135
1136
1137
1138
1139
    short i = 0;
#define NEXT cson_string_cstr(          \
                 cson_value_get_string( \
                   cson_array_get(ar,i) \
                   ))
    char const * tok = NEXT;
    while( tok ){
      if( g.isHTTP/*workaround for "abbreviated name" in CLI mode*/

          ? (0==strncmp("json",tok,4))
          : (0==strcmp(g.argv[1],tok))
          ){
        g.json.cmd.offset = i;
        break;
      }
      ++i;
      tok = NEXT;
    }
1372
1373
1374
1375
1376
1377
1378

1379
1380
1381

1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
  cson_object * o = NULL;
  int rc;
  resultCode = json_dumbdown_rc(resultCode ? resultCode : g.json.resultCode);
  o = cson_new_object();
  v = cson_object_value(o);
  if( ! o ) return NULL;
#define SET(K) if(!tmp) goto cleanup; \

  rc = cson_object_set( o, K, tmp ); \
  if(rc) do{\
    cson_value_free(tmp); \

    tmp = NULL; \
    goto cleanup; \
  }while(0)


  tmp = json_new_string(MANIFEST_UUID);
  SET("fossil");

  tmp = json_new_timestamp(-1);
  SET(FossilJsonKeys.timestamp);








>
|
<
|
>
|
|

<







1396
1397
1398
1399
1400
1401
1402
1403
1404

1405
1406
1407
1408
1409

1410
1411
1412
1413
1414
1415
1416
  cson_object * o = NULL;
  int rc;
  resultCode = json_dumbdown_rc(resultCode ? resultCode : g.json.resultCode);
  o = cson_new_object();
  v = cson_object_value(o);
  if( ! o ) return NULL;
#define SET(K) if(!tmp) goto cleanup; \
  cson_value_add_reference(tmp);      \
  rc = cson_object_set( o, K, tmp );  \

  cson_value_free(tmp);               \
  if(rc) do{                          \
    tmp = NULL;                       \
    goto cleanup;                     \
  }while(0)


  tmp = json_new_string(MANIFEST_UUID);
  SET("fossil");

  tmp = json_new_timestamp(-1);
  SET(FossilJsonKeys.timestamp);

1407
1408
1409
1410
1411
1412
1413



1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431

1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467

1468
1469

1470
1471
1472
1473
1474
1475
1476
  }

  if(g.json.cmd.commandStr){
    tmp = json_new_string(g.json.cmd.commandStr);
  }else{
    tmp = json_response_command_path();
  }



  SET("command");

  tmp = json_getenv(FossilJsonKeys.requestId);
  if( tmp ) cson_object_set( o, FossilJsonKeys.requestId, tmp );

  if(0){/* these are only intended for my own testing...*/
    if(g.json.cmd.v){
      tmp = g.json.cmd.v;
      SET("$commandPath");
    }
    if(g.json.param.v){
      tmp = g.json.param.v;
      SET("$params");
    }
    if(0){/*Only for debugging, add some info to the response.*/
      tmp = cson_value_new_integer( g.json.cmd.offset );
      cson_object_set( o, "cmd.offset", tmp );
      cson_object_set( o, "isCGI", cson_value_new_bool( g.isHTTP ) );

    }
  }

  if(fossil_timer_is_active(g.json.timerId)){
    /* This is, philosophically speaking, not quite the right place
       for ending the timer, but this is the one function which all of
       the JSON exit paths use (and they call it after processing,
       just before they end).
    */
    sqlite3_uint64 span = fossil_timer_stop(g.json.timerId);
    /* I'm actually seeing sub-uSec runtimes in some tests, but a time of
       0 is "just kinda wrong".
    */
    cson_object_set(o,"procTimeUs", cson_value_new_integer((cson_int_t)span));
    span /= 1000/*for milliseconds */;
    cson_object_set(o,"procTimeMs", cson_value_new_integer((cson_int_t)span));
    assert(!fossil_timer_is_active(g.json.timerId));
    g.json.timerId = -1;

  }
  if(g.json.warnings){
    tmp = cson_array_value(g.json.warnings);
    SET("warnings");
  }

  /* Only add the payload to SUCCESS responses. Else delete it. */
  if( NULL != payload ){
    if( resultCode ){
      cson_value_free(payload);
      payload = NULL;
    }else{
      tmp = payload;
      SET(FossilJsonKeys.payload);
    }
  }


  if(json_find_option_bool("debugFossilG","json-debug-g",NULL,0)
     &&(g.perm.Admin||g.perm.Setup)){

    tmp = json_g_to_json();
    SET("g");
  }

#undef SET
  goto ok;
  cleanup:







>
>
>
















|
|
>


















<

















>
|
<
>







1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477

1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496

1497
1498
1499
1500
1501
1502
1503
1504
  }

  if(g.json.cmd.commandStr){
    tmp = json_new_string(g.json.cmd.commandStr);
  }else{
    tmp = json_response_command_path();
  }
  if(!tmp){
    tmp = json_new_string("???");
  }
  SET("command");

  tmp = json_getenv(FossilJsonKeys.requestId);
  if( tmp ) cson_object_set( o, FossilJsonKeys.requestId, tmp );

  if(0){/* these are only intended for my own testing...*/
    if(g.json.cmd.v){
      tmp = g.json.cmd.v;
      SET("$commandPath");
    }
    if(g.json.param.v){
      tmp = g.json.param.v;
      SET("$params");
    }
    if(0){/*Only for debugging, add some info to the response.*/
      tmp = cson_value_new_integer( g.json.cmd.offset );
      SET("cmd.offset");
      tmp = cson_value_new_bool( g.isHTTP );
      SET("isCGI");
    }
  }

  if(fossil_timer_is_active(g.json.timerId)){
    /* This is, philosophically speaking, not quite the right place
       for ending the timer, but this is the one function which all of
       the JSON exit paths use (and they call it after processing,
       just before they end).
    */
    sqlite3_uint64 span = fossil_timer_stop(g.json.timerId);
    /* I'm actually seeing sub-uSec runtimes in some tests, but a time of
       0 is "just kinda wrong".
    */
    cson_object_set(o,"procTimeUs", cson_value_new_integer((cson_int_t)span));
    span /= 1000/*for milliseconds */;
    cson_object_set(o,"procTimeMs", cson_value_new_integer((cson_int_t)span));
    assert(!fossil_timer_is_active(g.json.timerId));
    g.json.timerId = -1;

  }
  if(g.json.warnings){
    tmp = cson_array_value(g.json.warnings);
    SET("warnings");
  }

  /* Only add the payload to SUCCESS responses. Else delete it. */
  if( NULL != payload ){
    if( resultCode ){
      cson_value_free(payload);
      payload = NULL;
    }else{
      tmp = payload;
      SET(FossilJsonKeys.payload);
    }
  }

  if((g.perm.Admin||g.perm.Setup)
     && json_find_option_bool("debugFossilG","json-debug-g",NULL,0)

     ){
    tmp = json_g_to_json();
    SET("g");
  }

#undef SET
  goto ok;
  cleanup:
1503
1504
1505
1506
1507
1508
1509

1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520

1521
1522
1523
1524
1525
1526
1527
** is NULL then json_err_cstr(code) is used.
*/
void json_err( int code, char const * msg, int alsoOutput ){
  int rc = code ? code : (g.json.resultCode
                          ? g.json.resultCode
                          : FSL_JSON_E_UNKNOWN);
  cson_value * resp = NULL;

  rc = json_dumbdown_rc(rc);
  if( rc && !msg ){
    msg = g.zErrMsg;
    if(!msg){
      msg = json_err_cstr(rc);
    }
  }
  resp = json_create_response(rc, msg, NULL);
  if(!resp){
    /* about the only error case here is out-of-memory. DO NOT
       call fossil_panic() here because that calls this function.

    */
    fprintf(stderr, "%s: Fatal error: could not allocate "
            "response object.\n", g.argv[0]);
    fossil_exit(1);
  }
  if( g.isHTTP ){
    if(alsoOutput){







>










|
>







1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
** is NULL then json_err_cstr(code) is used.
*/
void json_err( int code, char const * msg, int alsoOutput ){
  int rc = code ? code : (g.json.resultCode
                          ? g.json.resultCode
                          : FSL_JSON_E_UNKNOWN);
  cson_value * resp = NULL;
  if(g.json.isJsonMode==0) return;
  rc = json_dumbdown_rc(rc);
  if( rc && !msg ){
    msg = g.zErrMsg;
    if(!msg){
      msg = json_err_cstr(rc);
    }
  }
  resp = json_create_response(rc, msg, NULL);
  if(!resp){
    /* about the only error case here is out-of-memory. DO NOT
       call fossil_panic() or fossil_fatal() here because those
       allocate.
    */
    fprintf(stderr, "%s: Fatal error: could not allocate "
            "response object.\n", g.argv[0]);
    fossil_exit(1);
  }
  if( g.isHTTP ){
    if(alsoOutput){
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
  db_finalize(&q);
  cson_object_set( obj, "permissionFlags", sub );
  obj = cson_value_get_object(sub);

#define ADD(X,K) cson_object_set(obj, K, cson_value_new_bool(g.perm.X))
  ADD(Setup,"setup");
  ADD(Admin,"admin");
  ADD(Delete,"delete");
  ADD(Password,"password");
  ADD(Query,"query"); /* don't think this one is actually used */
  ADD(Write,"checkin");
  ADD(Read,"checkout");
  ADD(Hyperlink,"history");
  ADD(Clone,"clone");
  ADD(RdWiki,"readWiki");







<







1896
1897
1898
1899
1900
1901
1902

1903
1904
1905
1906
1907
1908
1909
  db_finalize(&q);
  cson_object_set( obj, "permissionFlags", sub );
  obj = cson_value_get_object(sub);

#define ADD(X,K) cson_object_set(obj, K, cson_value_new_bool(g.perm.X))
  ADD(Setup,"setup");
  ADD(Admin,"admin");

  ADD(Password,"password");
  ADD(Query,"query"); /* don't think this one is actually used */
  ADD(Write,"checkin");
  ADD(Read,"checkout");
  ADD(Hyperlink,"history");
  ADD(Clone,"clone");
  ADD(RdWiki,"readWiki");
Changes to src/json_artifact.c.
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242

/*
** Internal mapping of /json/artifact/FOO commands/callbacks.
*/
static ArtifactDispatchEntry ArtifactDispatchList[] = {
{"checkin", json_artifact_ci},
{"file", json_artifact_file},
{"tag", NULL},

{"ticket", json_artifact_ticket},
{"wiki", json_artifact_wiki},
/* Final entry MUST have a NULL name. */
{NULL,NULL}
};

/*







|
>







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

/*
** Internal mapping of /json/artifact/FOO commands/callbacks.
*/
static ArtifactDispatchEntry ArtifactDispatchList[] = {
{"checkin", json_artifact_ci},
{"file", json_artifact_file},
/*{"tag", NULL}, //impl missing */
/*{"technote", NULL}, //impl missing */
{"ticket", json_artifact_ticket},
{"wiki", json_artifact_wiki},
/* Final entry MUST have a NULL name. */
{NULL,NULL}
};

/*
474
475
476
477
478
479
480








481
482
483
484
485
486
487
  for( ; dispatcher->name; ++dispatcher ){
    if(0!=fossil_strcmp(dispatcher->name, zType)){
      continue;
    }else{
      entry = (*dispatcher->func)(pay, rid);
      break;
    }








  }
  if(!g.json.resultCode){
    assert( NULL != entry );
    assert( NULL != zType );
    cson_object_set( pay, "type", json_new_string(zType) );
    cson_object_set( pay, "uuid", json_new_string(zUuid) );
    /*cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );*/







>
>
>
>
>
>
>
>







475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  for( ; dispatcher->name; ++dispatcher ){
    if(0!=fossil_strcmp(dispatcher->name, zType)){
      continue;
    }else{
      entry = (*dispatcher->func)(pay, rid);
      break;
    }
  }
  if(entry==0){
    g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND
      /* This is not quite right. We need a new result code
         for this case. */;
    g.zErrMsg = mprintf("Missing implementation for "
                        "artifacts of this type.");
    goto error;
  }
  if(!g.json.resultCode){
    assert( NULL != entry );
    assert( NULL != zType );
    cson_object_set( pay, "type", json_new_string(zType) );
    cson_object_set( pay, "uuid", json_new_string(zUuid) );
    /*cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );*/
Changes to src/json_branch.c.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    return NULL;
  }
  payV = cson_value_new_object();
  pay = cson_value_get_object(payV);
  listV = cson_value_new_array();
  list = cson_value_get_array(listV);
  if(fossil_has_json()){
      range = json_getenv_cstr("range");
  }

  range = json_find_option_cstr("range",NULL,"r");
  if((!range||!*range) && !g.isHTTP){
    range = find_option("all","a",0);
    if(range && *range){
      range = "a";







|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    return NULL;
  }
  payV = cson_value_new_object();
  pay = cson_value_get_object(payV);
  listV = cson_value_new_array();
  list = cson_value_get_array(listV);
  if(fossil_has_json()){
    range = json_getenv_cstr("range");
  }

  range = json_find_option_cstr("range",NULL,"r");
  if((!range||!*range) && !g.isHTTP){
    range = find_option("all","a",0);
    if(range && *range){
      range = "a";
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  if( content_is_private(rootid) ) zOpt->isPrivate = 1;
  if( zOpt->isPrivate && zColor==0 ) zColor = "#fec084";
  if( zColor!=0 ){
    blob_appendf(&branch, "T *bgcolor * %F\n", zColor);
  }
  blob_appendf(&branch, "T *branch * %F\n", zBranch);
  blob_appendf(&branch, "T *sym-%F *\n", zBranch);
  if( zOpt->isPrivate ){
    blob_appendf(&branch, "T +private *\n");
  }

  /* Cancel all other symbolic tags */
  db_prepare(&q,
      "SELECT tagname FROM tagxref, tag"
      " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
      "   AND tagtype>0 AND tagname GLOB 'sym-*'"
      " ORDER BY tagname",
      rootid);
  while( db_step(&q)==SQLITE_ROW ){
    const char *zTag = db_column_text(&q, 0);
    blob_appendf(&branch, "T -%F *\n", zTag);
  }
  db_finalize(&q);

  blob_appendf(&branch, "U %F\n", g.zLogin);
  md5sum_blob(&branch, &mcksum);
  blob_appendf(&branch, "Z %b\n", &mcksum);

  brid = content_put(&branch);
  if( brid==0 ){
    fossil_panic("Problem committing manifest: %s", g.zErrMsg);
  }
  db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
  if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
    fossil_panic("%s", g.zErrMsg);
  }







<
<
<


















|







264
265
266
267
268
269
270



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  if( content_is_private(rootid) ) zOpt->isPrivate = 1;
  if( zOpt->isPrivate && zColor==0 ) zColor = "#fec084";
  if( zColor!=0 ){
    blob_appendf(&branch, "T *bgcolor * %F\n", zColor);
  }
  blob_appendf(&branch, "T *branch * %F\n", zBranch);
  blob_appendf(&branch, "T *sym-%F *\n", zBranch);




  /* Cancel all other symbolic tags */
  db_prepare(&q,
      "SELECT tagname FROM tagxref, tag"
      " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
      "   AND tagtype>0 AND tagname GLOB 'sym-*'"
      " ORDER BY tagname",
      rootid);
  while( db_step(&q)==SQLITE_ROW ){
    const char *zTag = db_column_text(&q, 0);
    blob_appendf(&branch, "T -%F *\n", zTag);
  }
  db_finalize(&q);

  blob_appendf(&branch, "U %F\n", g.zLogin);
  md5sum_blob(&branch, &mcksum);
  blob_appendf(&branch, "Z %b\n", &mcksum);

  brid = content_put_ex(&branch, 0, 0, 0, zOpt->isPrivate);
  if( brid==0 ){
    fossil_panic("Problem committing manifest: %s", g.zErrMsg);
  }
  db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
  if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
    fossil_panic("%s", g.zErrMsg);
  }
Changes to src/json_login.c.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    ;
  /*
    FIXME: we want to check the GET/POST args in this order:

    - GET: name, n, password, p
    - POST: name, password

    but a bug in cgi_parameter() is breaking that, causing PD() to
    return the last element of the PATH_INFO instead.

    Summary: If we check for P("name") first, then P("n"),
    then ONLY a GET param of "name" will match ("n"
    is not recognized). If we reverse the order of the
    checks then both forms work. Strangely enough, the
    "p"/"password" check is not affected by this.
   */
  char const * name = cson_value_get_cstr(json_req_payload_get("name"));
  char const * pw = NULL;
  char const * anonSeed = NULL;
  cson_value * payload = NULL;
  int uid = 0;
  /* reminder to self: Fossil internally (for the sake of /wiki)
     interprets paths in the form /foo/bar/baz such that P("name") ==







|
|

|
|
<
|

|







41
42
43
44
45
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
61
62
    ;
  /*
    FIXME: we want to check the GET/POST args in this order:

    - GET: name, n, password, p
    - POST: name, password

    but fossil's age-old behaviour of treating the last element of
    PATH_INFO as the value for the name parameter breaks that.

    Summary: If we check for P("name") first, then P("n"), then ONLY a
    GET param of "name" will match ("n" is not recognized). If we

    reverse the order of the checks then both forms work. The
    "p"/"password" check is not affected by this.
  */
  char const * name = cson_value_get_cstr(json_req_payload_get("name"));
  char const * pw = NULL;
  char const * anonSeed = NULL;
  cson_value * payload = NULL;
  int uid = 0;
  /* reminder to self: Fossil internally (for the sake of /wiki)
     interprets paths in the form /foo/bar/baz such that P("name") ==
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*
** Implements the /json/whoami page/command.
*/
cson_value * json_page_whoami(){
  cson_value * payload = NULL;
  cson_object * obj = NULL;
  Stmt q;
  if(!g.json.authToken){
      /* assume we just logged out. */
      db_prepare(&q, "SELECT login, cap FROM user WHERE login='nobody'");
  }
  else{
      db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d",
                 g.userUid);
  }







|







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*
** Implements the /json/whoami page/command.
*/
cson_value * json_page_whoami(){
  cson_value * payload = NULL;
  cson_object * obj = NULL;
  Stmt q;
  if(!g.json.authToken && g.userUid==0){
      /* assume we just logged out. */
      db_prepare(&q, "SELECT login, cap FROM user WHERE login='nobody'");
  }
  else{
      db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d",
                 g.userUid);
  }
Changes to src/json_timeline.c.
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
static const JsonPageDef JsonPageDefs_Timeline[] = {
/* the short forms are only enabled in CLI mode, to avoid
   that we end up with HTTP clients using 3 different names
   for the same requests.
*/
{"branch", json_timeline_branch, 0},
{"checkin", json_timeline_ci, 0},

{"event", json_timeline_event, 0},
{"ticket", json_timeline_ticket, 0},
{"wiki", json_timeline_wiki, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};









>
|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
static const JsonPageDef JsonPageDefs_Timeline[] = {
/* the short forms are only enabled in CLI mode, to avoid
   that we end up with HTTP clients using 3 different names
   for the same requests.
*/
{"branch", json_timeline_branch, 0},
{"checkin", json_timeline_ci, 0},
{"event" /* old name for technotes */, json_timeline_event, 0},
{"technote", json_timeline_event, 0},
{"ticket", json_timeline_ticket, 0},
{"wiki", json_timeline_wiki, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};


Changes to src/login.c.
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  if( zGoto ){
    cgi_redirect(zGoto);
  }else{
    fossil_redirect_home();
  }
}

/*
** The IP address of the client is stored as part of login cookies.
** But some clients are behind firewalls that shift the IP address
** with each HTTP request.  To allow such (broken) clients to log in,
** extract just a prefix of the IP address.
*/
static char *ipPrefix(const char *zIP){
  int i, j;
  static int ip_prefix_terms = -1;
  if( ip_prefix_terms<0 ){
    ip_prefix_terms = db_get_int("ip-prefix-terms",2);
  }
  if( ip_prefix_terms==0 ) return mprintf("0");
  for(i=j=0; zIP[i]; i++){
    if( zIP[i]=='.' ){
      j++;
      if( j==ip_prefix_terms ) break;
    }
  }
  return mprintf("%.*s", i, zIP);
}

/*
** Return an abbreviated project code.  The abbreviation is the first
** 16 characters of the project code.
**
** Memory is obtained from malloc.
*/
static char *abbreviated_project_code(const char *zFullCode){







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







109
110
111
112
113
114
115






















116
117
118
119
120
121
122
  if( zGoto ){
    cgi_redirect(zGoto);
  }else{
    fossil_redirect_home();
  }
}























/*
** Return an abbreviated project code.  The abbreviation is the first
** 16 characters of the project code.
**
** Memory is obtained from malloc.
*/
static char *abbreviated_project_code(const char *zFullCode){
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
){
  const char *zCookieName = login_cookie_name();
  const char *zExpire = db_get("cookie-expire","8766");
  int expires = atoi(zExpire)*3600;
  char *zHash;
  char *zCookie;
  const char *zIpAddr = PD("REMOTE_ADDR","nil"); /* IP address of user */
  char *zRemoteAddr = ipPrefix(zIpAddr);         /* Abbreviated IP address */

  assert((zUsername && *zUsername) && (uid > 0) && "Invalid user data.");
  zHash = db_text(0,
      "SELECT cookie FROM user"
      " WHERE uid=%d"
      "   AND ipaddr=%Q"
      "   AND cexpire>julianday('now')"
      "   AND length(cookie)>30",
      uid, zRemoteAddr);
  if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))");
  zCookie = login_gen_user_cookie_value(zUsername, zHash);
  cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
  record_login_attempt(zUsername, zIpAddr, 1);
  db_multi_exec(
                "UPDATE user SET cookie=%Q, ipaddr=%Q, "
                "  cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
                zHash, zRemoteAddr, expires, uid
                );
  free(zRemoteAddr);
  free(zHash);
  if( zDest ){
    *zDest = zCookie;
  }else{
    free(zCookie);
  }
}

/* Sets a cookie for an anonymous user login, which looks like this:
**
**    HASH/TIME/anonymous
**
** Where HASH is the sha1sum of TIME/IPADDR/SECRET, in which IPADDR
** is the abbreviated IP address and SECRET is captcha-secret.
**
** If either zIpAddr or zRemoteAddr are NULL then REMOTE_ADDR
** is used.
**
** If zCookieDest is not NULL then the generated cookie is assigned to
** *zCookieDest and the caller must eventually free() it.
*/
void login_set_anon_cookie(const char *zIpAddr, char **zCookieDest ){
  const char *zNow;            /* Current time (julian day number) */
  char *zCookie;               /* The login cookie */
  const char *zCookieName;     /* Name of the login cookie */
  Blob b;                      /* Blob used during cookie construction */
  char *zRemoteAddr;           /* Abbreviated IP address */
  if(!zIpAddr){
    zIpAddr = PD("REMOTE_ADDR","nil");
  }
  zRemoteAddr = ipPrefix(zIpAddr);
  zCookieName = login_cookie_name();
  zNow = db_text("0", "SELECT julianday('now')");
  assert( zCookieName && zRemoteAddr && zIpAddr && zNow );
  blob_init(&b, zNow, -1);
  blob_appendf(&b, "/%s/%s", zRemoteAddr, db_get("captcha-secret",""));
  sha1sum_blob(&b, &b);
  zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
  blob_reset(&b);
  cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), 6*3600);
  if( zCookieDest ){
    *zCookieDest = zCookie;
  }else{







<





<


|





|

|

<












|
<
<
<
<









<
<
<
<
<


|

|







271
272
273
274
275
276
277

278
279
280
281
282

283
284
285
286
287
288
289
290
291
292
293
294

295
296
297
298
299
300
301
302
303
304
305
306
307




308
309
310
311
312
313
314
315
316





317
318
319
320
321
322
323
324
325
326
327
328
){
  const char *zCookieName = login_cookie_name();
  const char *zExpire = db_get("cookie-expire","8766");
  int expires = atoi(zExpire)*3600;
  char *zHash;
  char *zCookie;
  const char *zIpAddr = PD("REMOTE_ADDR","nil"); /* IP address of user */


  assert((zUsername && *zUsername) && (uid > 0) && "Invalid user data.");
  zHash = db_text(0,
      "SELECT cookie FROM user"
      " WHERE uid=%d"

      "   AND cexpire>julianday('now')"
      "   AND length(cookie)>30",
      uid);
  if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))");
  zCookie = login_gen_user_cookie_value(zUsername, zHash);
  cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
  record_login_attempt(zUsername, zIpAddr, 1);
  db_multi_exec(
                "UPDATE user SET cookie=%Q,"
                "  cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
                zHash, expires, uid
                );

  free(zHash);
  if( zDest ){
    *zDest = zCookie;
  }else{
    free(zCookie);
  }
}

/* Sets a cookie for an anonymous user login, which looks like this:
**
**    HASH/TIME/anonymous
**
** Where HASH is the sha1sum of TIME/SECRET, in which SECRET is captcha-secret.




**
** If zCookieDest is not NULL then the generated cookie is assigned to
** *zCookieDest and the caller must eventually free() it.
*/
void login_set_anon_cookie(const char *zIpAddr, char **zCookieDest ){
  const char *zNow;            /* Current time (julian day number) */
  char *zCookie;               /* The login cookie */
  const char *zCookieName;     /* Name of the login cookie */
  Blob b;                      /* Blob used during cookie construction */





  zCookieName = login_cookie_name();
  zNow = db_text("0", "SELECT julianday('now')");
  assert( zCookieName && zNow );
  blob_init(&b, zNow, -1);
  blob_appendf(&b, "/%s", db_get("captcha-secret",""));
  sha1sum_blob(&b, &b);
  zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
  blob_reset(&b);
  cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), 6*3600);
  if( zCookieDest ){
    *zCookieDest = zCookie;
  }else{
436
437
438
439
440
441
442

443
444
445
446
447
448
449
    if( sqlite3_strglob("*Firefox/[1-9]*", zAgent)==0 ) return 1;
    if( sqlite3_strglob("*Chrome/[1-9]*", zAgent)==0 ) return 1;
    if( sqlite3_strglob("*(compatible;?MSIE?[1789]*", zAgent)==0 ) return 1;
    if( sqlite3_strglob("*Trident/[1-9]*;?rv:[1-9]*", zAgent)==0 ){
      return 1; /* IE11+ */
    }
    if( sqlite3_strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent)==0 ) return 1;

    return 0;
  }
  if( strncmp(zAgent, "Opera/", 6)==0 ) return 1;
  if( strncmp(zAgent, "Safari/", 7)==0 ) return 1;
  if( strncmp(zAgent, "Lynx/", 5)==0 ) return 1;
  if( strncmp(zAgent, "NetSurf/", 8)==0 ) return 1;
  return 0;







>







402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
    if( sqlite3_strglob("*Firefox/[1-9]*", zAgent)==0 ) return 1;
    if( sqlite3_strglob("*Chrome/[1-9]*", zAgent)==0 ) return 1;
    if( sqlite3_strglob("*(compatible;?MSIE?[1789]*", zAgent)==0 ) return 1;
    if( sqlite3_strglob("*Trident/[1-9]*;?rv:[1-9]*", zAgent)==0 ){
      return 1; /* IE11+ */
    }
    if( sqlite3_strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent)==0 ) return 1;
    if( sqlite3_strglob("*PaleMoon/[1-9]*", zAgent)==0 ) return 1;
    return 0;
  }
  if( strncmp(zAgent, "Opera/", 6)==0 ) return 1;
  if( strncmp(zAgent, "Safari/", 7)==0 ) return 1;
  if( strncmp(zAgent, "Lynx/", 5)==0 ) return 1;
  if( strncmp(zAgent, "NetSurf/", 8)==0 ) return 1;
  return 0;
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
** to self-registered users.
*/
int login_self_register_available(const char *zNeeded){
  CapabilityString *pCap;
  int rc;
  if( !db_get_boolean("self-register",0) ) return 0;
  if( zNeeded==0 ) return 1;
  pCap = capability_add(0, db_get("default-perms", 0));
  capability_expand(pCap);
  rc = capability_has_any(pCap, zNeeded);
  capability_free(pCap);
  return rc;
}

/*







|







479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
** to self-registered users.
*/
int login_self_register_available(const char *zNeeded){
  CapabilityString *pCap;
  int rc;
  if( !db_get_boolean("self-register",0) ) return 0;
  if( zNeeded==0 ) return 1;
  pCap = capability_add(0, db_get("default-perms", "u"));
  capability_expand(pCap);
  rc = capability_has_any(pCap, zNeeded);
  capability_free(pCap);
  return rc;
}

/*
699
700
701
702
703
704
705








706
707
708
709
710
711
712
713
714
715
716
717




718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
    @ <input type="hidden" name="anon" value="1" />
  }
  if( g.zLogin ){
    @ <p>Currently logged in as <b>%h(g.zLogin)</b>.
    @ <input type="submit" name="out" value="Logout"></p>
    @ </form>
  }else{








    @ <table class="login_out">
    @ <tr>
    @   <td class="form_label">User ID:</td>
    if( anonFlag ){
      @ <td><input type="text" id="u" name="u" value="anonymous" size="30"></td>
    }else{
      @ <td><input type="text" id="u" name="u" value="" size="30" /></td>
    }
    @ </tr>
    @ <tr>
    @  <td class="form_label">Password:</td>
    @  <td><input type="password" id="p" name="p" value="" size="30" /></td>




    @ </tr>
    if( P("HTTPS")==0 ){
      @ <tr><td class="form_label">Warning:</td>
      @ <td><span class='securityWarning'>
      @ Your password will be sent in the clear over an
      @ unencrypted connection.
      if( g.sslNotAvailable ){
        @ No encrypted connection is available on this server.
      }else{
        @ Consider logging in at
        @ <a href='%s(g.zHttpsURL)'>%h(g.zHttpsURL)</a> instead.
      }
      @ </span></td></tr>
    }
    if( g.zLogin==0 && (anonFlag || zGoto==0) ){
      zAnonPw = db_text(0, "SELECT pw FROM user"
                           " WHERE login='anonymous'"
                           "   AND cap!=''");
    }
    @ <tr>
    @   <td></td>
    @   <td><input type="submit" name="in" value="Login"></td>
    @ </tr>
    if( !noAnon && login_self_register_available(0) ){
      @ <tr>
      @   <td></td>
      @   <td><input type="submit" name="self" value="Create A New Account">
      @ </tr>
    }
    @ </table>
    if( zAnonPw && !noAnon ){
      unsigned int uSeed = captcha_seed();
      const char *zDecoded = captcha_decode(uSeed);
      int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
      char *zCaptcha = captcha_render(zDecoded);
  
      @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
      @ Visitors may enter <b>anonymous</b> as the user-ID with
      @ the 8-character hexadecimal password shown below:</p>







>
>
>
>
>
>
>
>











|
>
>
>
>














<
<
<
<
<












<







666
667
668
669
670
671
672
673
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
704
705
706
707
708
709
710





711
712
713
714
715
716
717
718
719
720
721
722

723
724
725
726
727
728
729
    @ <input type="hidden" name="anon" value="1" />
  }
  if( g.zLogin ){
    @ <p>Currently logged in as <b>%h(g.zLogin)</b>.
    @ <input type="submit" name="out" value="Logout"></p>
    @ </form>
  }else{
    unsigned int uSeed = captcha_seed();
    if( g.zLogin==0 && (anonFlag || zGoto==0) ){
      zAnonPw = db_text(0, "SELECT pw FROM user"
                           " WHERE login='anonymous'"
                           "   AND cap!=''");
    }else{
      zAnonPw = 0;
    }
    @ <table class="login_out">
    @ <tr>
    @   <td class="form_label">User ID:</td>
    if( anonFlag ){
      @ <td><input type="text" id="u" name="u" value="anonymous" size="30"></td>
    }else{
      @ <td><input type="text" id="u" name="u" value="" size="30" /></td>
    }
    @ </tr>
    @ <tr>
    @  <td class="form_label">Password:</td>
    @  <td><input type="password" id="p" name="p" value="" size="30" />\
    if( zAnonPw && !noAnon ){
      captcha_speakit_button(uSeed, "Speak password for \"anonymous\"");
    }
    @ </td>
    @ </tr>
    if( P("HTTPS")==0 ){
      @ <tr><td class="form_label">Warning:</td>
      @ <td><span class='securityWarning'>
      @ Your password will be sent in the clear over an
      @ unencrypted connection.
      if( g.sslNotAvailable ){
        @ No encrypted connection is available on this server.
      }else{
        @ Consider logging in at
        @ <a href='%s(g.zHttpsURL)'>%h(g.zHttpsURL)</a> instead.
      }
      @ </span></td></tr>
    }





    @ <tr>
    @   <td></td>
    @   <td><input type="submit" name="in" value="Login"></td>
    @ </tr>
    if( !noAnon && login_self_register_available(0) ){
      @ <tr>
      @   <td></td>
      @   <td><input type="submit" name="self" value="Create A New Account">
      @ </tr>
    }
    @ </table>
    if( zAnonPw && !noAnon ){

      const char *zDecoded = captcha_decode(uSeed);
      int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
      char *zCaptcha = captcha_render(zDecoded);
  
      @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
      @ Visitors may enter <b>anonymous</b> as the user-ID with
      @ the 8-character hexadecimal password shown below:</p>
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
** repository.
**
** Return true if a transfer was made and false if not.
*/
static int login_transfer_credentials(
  const char *zLogin,          /* Login we are looking for */
  const char *zCode,           /* Project code of peer repository */
  const char *zHash,           /* HASH from login cookie HASH/CODE/LOGIN */
  const char *zRemoteAddr      /* Request comes from here */
){
  sqlite3 *pOther = 0;         /* The other repository */
  sqlite3_stmt *pStmt;         /* Query against the other repository */
  char *zSQL;                  /* SQL of the query against other repo */
  char *zOtherRepo;            /* Filename of the other repository */
  int rc;                      /* Result code from SQLite library functions */
  int nXfer = 0;               /* Number of credentials transferred */







|
<







773
774
775
776
777
778
779
780

781
782
783
784
785
786
787
** repository.
**
** Return true if a transfer was made and false if not.
*/
static int login_transfer_credentials(
  const char *zLogin,          /* Login we are looking for */
  const char *zCode,           /* Project code of peer repository */
  const char *zHash            /* HASH from login cookie HASH/CODE/LOGIN */

){
  sqlite3 *pOther = 0;         /* The other repository */
  sqlite3_stmt *pStmt;         /* Query against the other repository */
  char *zSQL;                  /* SQL of the query against other repo */
  char *zOtherRepo;            /* Filename of the other repository */
  int rc;                      /* Result code from SQLite library functions */
  int nXfer = 0;               /* Number of credentials transferred */
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
    sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
    sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);
    sqlite3_busy_timeout(pOther, 5000);
    zSQL = mprintf(
      "SELECT cexpire FROM user"
      " WHERE login=%Q"
      "   AND ipaddr=%Q"
      "   AND length(cap)>0"
      "   AND length(pw)>0"
      "   AND cexpire>julianday('now')"
      "   AND constant_time_cmp(cookie,%Q)=0",
      zLogin, zRemoteAddr, zHash
    );
    pStmt = 0;
    rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0);
    if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
      db_multi_exec(
        "UPDATE user SET cookie=%Q, ipaddr=%Q, cexpire=%.17g"
        " WHERE login=%Q",
        zHash, zRemoteAddr,
        sqlite3_column_double(pStmt, 0), zLogin
      );
      nXfer++;
    }
    sqlite3_finalize(pStmt);
  }
  sqlite3_close(pOther);







<




|





|

|







801
802
803
804
805
806
807

808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
    sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
    sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);
    sqlite3_busy_timeout(pOther, 5000);
    zSQL = mprintf(
      "SELECT cexpire FROM user"
      " WHERE login=%Q"

      "   AND length(cap)>0"
      "   AND length(pw)>0"
      "   AND cexpire>julianday('now')"
      "   AND constant_time_cmp(cookie,%Q)=0",
      zLogin, zHash
    );
    pStmt = 0;
    rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0);
    if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
      db_multi_exec(
        "UPDATE user SET cookie=%Q, cexpire=%.17g"
        " WHERE login=%Q",
        zHash, 
        sqlite3_column_double(pStmt, 0), zLogin
      );
      nXfer++;
    }
    sqlite3_finalize(pStmt);
  }
  sqlite3_close(pOther);
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
  if( fossil_strcmp(zLogin, "nobody")==0 ) return 1;
  if( fossil_strcmp(zLogin, "developer")==0 ) return 1;
  if( fossil_strcmp(zLogin, "reader")==0 ) return 1;
  return 0;
}

/*
** Lookup the uid for a non-built-in user with zLogin and zCookie and
** zRemoteAddr.  Return 0 if not found.
**
** Note that this only searches for logged-in entries with matching
** zCookie (db: user.cookie) and zRemoteAddr (db: user.ipaddr)
** entries.
*/
static int login_find_user(
  const char *zLogin,            /* User name */
  const char *zCookie,           /* Login cookie value */
  const char *zRemoteAddr        /* Abbreviated IP address for valid login */
){
  int uid;
  if( login_is_special(zLogin) ) return 0;
  uid = db_int(0,
    "SELECT uid FROM user"
    " WHERE login=%Q"
    "   AND ipaddr=%Q"
    "   AND cexpire>julianday('now')"
    "   AND length(cap)>0"
    "   AND length(pw)>0"
    "   AND constant_time_cmp(cookie,%Q)=0",
    zLogin, zRemoteAddr, zCookie
  );
  return uid;
}

/*
** Attempt to use Basic Authentication to establish the user.  Return the
** (non-zero) uid if successful.  Return 0 if it does not work.







|
|


|
<



|
<






<




|







837
838
839
840
841
842
843
844
845
846
847
848

849
850
851
852

853
854
855
856
857
858

859
860
861
862
863
864
865
866
867
868
869
870
  if( fossil_strcmp(zLogin, "nobody")==0 ) return 1;
  if( fossil_strcmp(zLogin, "developer")==0 ) return 1;
  if( fossil_strcmp(zLogin, "reader")==0 ) return 1;
  return 0;
}

/*
** Lookup the uid for a non-built-in user with zLogin and zCookie.
** Return 0 if not found.
**
** Note that this only searches for logged-in entries with matching
** zCookie (db: user.cookie) entries.

*/
static int login_find_user(
  const char *zLogin,            /* User name */
  const char *zCookie            /* Login cookie value */

){
  int uid;
  if( login_is_special(zLogin) ) return 0;
  uid = db_int(0,
    "SELECT uid FROM user"
    " WHERE login=%Q"

    "   AND cexpire>julianday('now')"
    "   AND length(cap)>0"
    "   AND length(pw)>0"
    "   AND constant_time_cmp(cookie,%Q)=0",
    zLogin, zCookie
  );
  return uid;
}

/*
** Attempt to use Basic Authentication to establish the user.  Return the
** (non-zero) uid if successful.  Return 0 if it does not work.
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
**    g.isHuman      True if the user is human, not a spider or robot
**
*/
void login_check_credentials(void){
  int uid = 0;                  /* User id */
  const char *zCookie;          /* Text of the login cookie */
  const char *zIpAddr;          /* Raw IP address of the requestor */
  char *zRemoteAddr;            /* Abbreviated IP address of the requestor */
  const char *zCap = 0;         /* Capability string */
  const char *zPublicPages = 0; /* GLOB patterns of public pages */
  const char *zLogin = 0;       /* Login user for credentials */

  /* Only run this check once.  */
  if( g.userUid!=0 ) return;

  sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);

  /* If the HTTP connection is coming over 127.0.0.1 and if
  ** local login is disabled and if we are using HTTP and not HTTPS,
  ** then there is no need to check user credentials.
  **
  ** This feature allows the "fossil ui" command to give the user
  ** full access rights without having to log in.
  */
  zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil"));
  if( ( cgi_is_loopback(zIpAddr)
       || (g.fSshClient & CGI_SSH_CLIENT)!=0 )
   && g.useLocalauth
   && db_get_int("localauth",0)==0
   && P("HTTPS")==0
  ){
    if( g.localOpen ) zLogin = db_lget("default-user",0);







<

















|







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
**    g.isHuman      True if the user is human, not a spider or robot
**
*/
void login_check_credentials(void){
  int uid = 0;                  /* User id */
  const char *zCookie;          /* Text of the login cookie */
  const char *zIpAddr;          /* Raw IP address of the requestor */

  const char *zCap = 0;         /* Capability string */
  const char *zPublicPages = 0; /* GLOB patterns of public pages */
  const char *zLogin = 0;       /* Login user for credentials */

  /* Only run this check once.  */
  if( g.userUid!=0 ) return;

  sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);

  /* If the HTTP connection is coming over 127.0.0.1 and if
  ** local login is disabled and if we are using HTTP and not HTTPS,
  ** then there is no need to check user credentials.
  **
  ** This feature allows the "fossil ui" command to give the user
  ** full access rights without having to log in.
  */
  zIpAddr = PD("REMOTE_ADDR","nil");
  if( ( cgi_is_loopback(zIpAddr)
       || (g.fSshClient & CGI_SSH_CLIENT)!=0 )
   && g.useLocalauth
   && db_get_int("localauth",0)==0
   && P("HTTPS")==0
  ){
    if( g.localOpen ) zLogin = db_lget("default-user",0);
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
      /* Cookies of the form "HASH/TIME/anonymous".  The TIME must not be
      ** too old and the sha1 hash of TIME/IPADDR/SECRET must match HASH.
      ** SECRET is the "captcha-secret" value in the repository.
      */
      double rTime = atof(zArg);
      Blob b;
      blob_zero(&b);
      blob_appendf(&b, "%s/%s/%s",
                   zArg, zRemoteAddr, db_get("captcha-secret",""));
      sha1sum_blob(&b, &b);
      if( fossil_strcmp(zHash, blob_str(&b))==0 ){
        uid = db_int(0,
            "SELECT uid FROM user WHERE login='anonymous'"
            " AND length(cap)>0"
            " AND length(pw)>0"
            " AND %.17g+0.25>julianday('now')",
            rTime
        );
      }
      blob_reset(&b);
    }else{
      /* Cookies of the form "HASH/CODE/USER".  Search first in the
      ** local user table, then the user table for project CODE if we
      ** are part of a login-group.
      */
      uid = login_find_user(zUser, zHash, zRemoteAddr);
      if( uid==0 && login_transfer_credentials(zUser,zArg,zHash,zRemoteAddr) ){
        uid = login_find_user(zUser, zHash, zRemoteAddr);
        if( uid ) record_login_attempt(zUser, zIpAddr, 1);
      }
    }
    sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "%.10s", zHash);
  }

  /* If no user found and the REMOTE_USER environment variable is set,







|
<
















|
|
|







995
996
997
998
999
1000
1001
1002

1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
      /* Cookies of the form "HASH/TIME/anonymous".  The TIME must not be
      ** too old and the sha1 hash of TIME/IPADDR/SECRET must match HASH.
      ** SECRET is the "captcha-secret" value in the repository.
      */
      double rTime = atof(zArg);
      Blob b;
      blob_zero(&b);
      blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));

      sha1sum_blob(&b, &b);
      if( fossil_strcmp(zHash, blob_str(&b))==0 ){
        uid = db_int(0,
            "SELECT uid FROM user WHERE login='anonymous'"
            " AND length(cap)>0"
            " AND length(pw)>0"
            " AND %.17g+0.25>julianday('now')",
            rTime
        );
      }
      blob_reset(&b);
    }else{
      /* Cookies of the form "HASH/CODE/USER".  Search first in the
      ** local user table, then the user table for project CODE if we
      ** are part of a login-group.
      */
      uid = login_find_user(zUser, zHash);
      if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
        uid = login_find_user(zUser, zHash);
        if( uid ) record_login_attempt(zUser, zIpAddr, 1);
      }
    }
    sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "%.10s", zHash);
  }

  /* If no user found and the REMOTE_USER environment variable is set,
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
  */
  zPublicPages = db_get("public-pages",0);
  if( zPublicPages!=0 ){
    Glob *pGlob = glob_create(zPublicPages);
    const char *zUri = PD("REQUEST_URI","");
    zUri += (int)strlen(g.zTop);
    if( glob_match(pGlob, zUri) ){
      login_set_capabilities(db_get("default-perms", 0), 0);
    }
    glob_free(pGlob);
  }
}

/*
** Memory of settings







|







1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
  */
  zPublicPages = db_get("public-pages",0);
  if( zPublicPages!=0 ){
    Glob *pGlob = glob_create(zPublicPages);
    const char *zUri = PD("REQUEST_URI","");
    zUri += (int)strlen(g.zTop);
    if( glob_match(pGlob, zUri) ){
      login_set_capabilities(db_get("default-perms", "u"), 0);
    }
    glob_free(pGlob);
  }
}

/*
** Memory of settings
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
    switch( zCap[i] ){
      case 's':   p->Setup = 1; /* Fall thru into Admin */
      case 'a':   p->Admin = p->RdTkt = p->WrTkt = p->Zip =
                             p->RdWiki = p->WrWiki = p->NewWiki =
                             p->ApndWiki = p->Hyperlink = p->Clone =
                             p->NewTkt = p->Password = p->RdAddr =
                             p->TktFmt = p->Attach = p->ApndTkt =
                             p->ModWiki = p->ModTkt = p->Delete =
                             p->RdForum = p->WrForum = p->ModForum =
                             p->WrTForum = p->AdminForum =
                             p->EmailAlert = p->Announce = p->Debug = 1;
                             /* Fall thru into Read/Write */
      case 'i':   p->Read = p->Write = 1;                      break;
      case 'o':   p->Read = 1;                                 break;
      case 'z':   p->Zip = 1;                                  break;

      case 'd':   p->Delete = 1;                               break;
      case 'h':   p->Hyperlink = 1;                            break;
      case 'g':   p->Clone = 1;                                break;
      case 'p':   p->Password = 1;                             break;

      case 'j':   p->RdWiki = 1;                               break;
      case 'k':   p->WrWiki = p->RdWiki = p->ApndWiki =1;      break;
      case 'm':   p->ApndWiki = 1;                             break;







|








<







1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205

1206
1207
1208
1209
1210
1211
1212
    switch( zCap[i] ){
      case 's':   p->Setup = 1; /* Fall thru into Admin */
      case 'a':   p->Admin = p->RdTkt = p->WrTkt = p->Zip =
                             p->RdWiki = p->WrWiki = p->NewWiki =
                             p->ApndWiki = p->Hyperlink = p->Clone =
                             p->NewTkt = p->Password = p->RdAddr =
                             p->TktFmt = p->Attach = p->ApndTkt =
                             p->ModWiki = p->ModTkt =
                             p->RdForum = p->WrForum = p->ModForum =
                             p->WrTForum = p->AdminForum =
                             p->EmailAlert = p->Announce = p->Debug = 1;
                             /* Fall thru into Read/Write */
      case 'i':   p->Read = p->Write = 1;                      break;
      case 'o':   p->Read = 1;                                 break;
      case 'z':   p->Zip = 1;                                  break;


      case 'h':   p->Hyperlink = 1;                            break;
      case 'g':   p->Clone = 1;                                break;
      case 'p':   p->Password = 1;                             break;

      case 'j':   p->RdWiki = 1;                               break;
      case 'k':   p->WrWiki = p->RdWiki = p->ApndWiki =1;      break;
      case 'm':   p->ApndWiki = 1;                             break;
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
  FossilUserPerms *p = (flgs & LOGIN_ANON) ? &g.anon : &g.perm;
  if( nCap<0 ) nCap = strlen(zCap);
  for(i=0; i<nCap && rc && zCap[i]; i++){
    switch( zCap[i] ){
      case 'a':  rc = p->Admin;     break;
      case 'b':  rc = p->Attach;    break;
      case 'c':  rc = p->ApndTkt;   break;
      case 'd':  rc = p->Delete;    break;
      case 'e':  rc = p->RdAddr;    break;
      case 'f':  rc = p->NewWiki;   break;
      case 'g':  rc = p->Clone;     break;
      case 'h':  rc = p->Hyperlink; break;
      case 'i':  rc = p->Write;     break;
      case 'j':  rc = p->RdWiki;    break;
      case 'k':  rc = p->WrWiki;    break;







|







1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
  FossilUserPerms *p = (flgs & LOGIN_ANON) ? &g.anon : &g.perm;
  if( nCap<0 ) nCap = strlen(zCap);
  for(i=0; i<nCap && rc && zCap[i]; i++){
    switch( zCap[i] ){
      case 'a':  rc = p->Admin;     break;
      case 'b':  rc = p->Attach;    break;
      case 'c':  rc = p->ApndTkt;   break;
      /* d unused: see comment in capabilities.c */
      case 'e':  rc = p->RdAddr;    break;
      case 'f':  rc = p->NewWiki;   break;
      case 'g':  rc = p->Clone;     break;
      case 'h':  rc = p->Hyperlink; break;
      case 'i':  rc = p->Write;     break;
      case 'j':  rc = p->RdWiki;    break;
      case 'k':  rc = p->WrWiki;    break;
1477
1478
1479
1480
1481
1482
1483











































1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498


1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545



1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572








1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591



1592
1593
1594
1595
1596
1597

1598
1599
1600
1601
1602
1603
1604
  if( g.okCsrf ) return;
  if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
    g.okCsrf = 1;
    return;
  }
  fossil_fatal("Cross-site request forgery attempt");
}












































/*
** WEBPAGE: register
**
** Page to allow users to self-register.  The "self-register" setting
** must be enabled for this page to operate.
*/
void register_page(void){
  const char *zUserID, *zPasswd, *zConfirm, *zEAddr;
  const char *zDName;
  unsigned int uSeed;
  const char *zDecoded;
  char *zCaptcha;
  int iErrLine = -1;
  const char *zErr = 0;


  char *zPerms;             /* Permissions for the default user */
  int canDoAlerts = 0;      /* True if receiving email alerts is possible */
  int doAlerts = 0;         /* True if subscription is wanted too */
  if( !db_get_boolean("self-register", 0) ){
    style_header("Registration not possible");
    @ <p>This project does not allow user self-registration. Please contact the
    @ project administrator to obtain an account.</p>
    style_footer();
    return;
  }
  zPerms = db_get("default-perms", 0);

  /* Prompt the user for email alerts if this repository is configured for
  ** email alerts and if the default permissions include "7" */
  canDoAlerts = alert_tables_exist() && db_int(0,
    "SELECT fullcap(%Q) GLOB '*7*'", zPerms
  );
  doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0;

  zUserID = PDT("u","");
  zPasswd = PDT("p","");
  zConfirm = PDT("cp","");
  zEAddr = PDT("ea","");
  zDName = PDT("dn","");

  /* Verify user imputs */
  if( P("new")==0 || !cgi_csrf_safe(1) ){
    /* This is not a valid form submission.  Fall through into
    ** the form display */
  }else if( !captcha_is_correct(1) ){
    iErrLine = 6;
    zErr = "Incorrect CAPTCHA";
  }else if( strlen(zUserID)<3 ){
    iErrLine = 1;
    zErr = "User ID too short. Must be at least 3 characters.";
  }else if( sqlite3_strglob("*[^-a-zA-Z0-9_.]*",zUserID)==0 ){
    iErrLine = 1;
    zErr = "User ID may not contain spaces or special characters.";
  }else if( zDName[0]==0 ){
    iErrLine = 2;
    zErr = "Required";
  }else if( zEAddr[0]==0 ){
    iErrLine = 3;
    zErr = "Required";
  }else if( email_copy_addr(zEAddr,0)==0 ){
    iErrLine = 3;
    zErr = "Not a valid email address";



  }else if( strlen(zPasswd)<6 ){
    iErrLine = 4;
    zErr = "Password must be at least 6 characters long";
  }else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
    iErrLine = 5;
    zErr = "Passwords do not match";
  }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zUserID) ){
    iErrLine = 1;
    zErr = "This User ID is already taken. Choose something different.";
  }else if(
      /* If the email is found anywhere in USER.INFO... */
      db_exists("SELECT 1 FROM user WHERE info LIKE '%%%q%%'", zEAddr)
    ||
      /* Or if the email is a verify subscriber email with an associated
      ** user... */
      db_exists(
        "SELECT 1 FROM subscriber WHERE semail=%Q AND suname IS NOT NULL"
        " AND sverified",zEAddr)
   ){
    iErrLine = 3;
    zErr = "This email address is already claimed by another user";
  }else{
    /* If all of the tests above have passed, that means that the submitted
    ** form contains valid data and we can proceed to create the new login */
    Blob sql;
    int uid;
    char *zPass = sha1_shared_secret(zPasswd, zUserID, 0);








    blob_init(&sql, 0, 0);
    blob_append_sql(&sql,
       "INSERT INTO user(login,pw,cap,info,mtime)\n"
       "VALUES(%Q,%Q,%Q,"
       "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())",
       zUserID, zPass, zPerms, zDName, zEAddr, g.zIpAddr);
    fossil_free(zPass);
    db_multi_exec("%s", blob_sql_text(&sql));
    uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID);
    login_set_user_cookie(zUserID, uid, NULL);
    if( doAlerts ){
      /* Also make the new user a subscriber. */
      Blob hdr, body;
      AlertSender *pSender;
      sqlite3_int64 id;   /* New subscriber Id */
      const char *zCode;  /* New subscriber code (in hex) */
      const char *zGoto = P("g");
      int nsub = 0;
      char ssub[20];



      ssub[nsub++] = 'a';
      if( g.perm.Read )    ssub[nsub++] = 'c';
      if( g.perm.RdForum ) ssub[nsub++] = 'f';
      if( g.perm.RdTkt )   ssub[nsub++] = 't';
      if( g.perm.RdWiki )  ssub[nsub++] = 'w';
      ssub[nsub] = 0;

      /* Also add the user to the subscriber table. */
      db_multi_exec(
        "INSERT INTO subscriber(semail,suname,"
        "  sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)"
        " VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)"
        " ON CONFLICT(semail) DO UPDATE"
        "   SET suname=excluded.suname",







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












<


>
>










|


















|


|

|









|


>
>
>






|




















>
>
>
>
>
>
>
>





|













>
>
>

|
|
|
|

>







1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503

1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
  if( g.okCsrf ) return;
  if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
    g.okCsrf = 1;
    return;
  }
  fossil_fatal("Cross-site request forgery attempt");
}

/*
** Check to see if the candidate username zUserID is already used.
** Return 1 if it is already in use.  Return 0 if the name is 
** available for a self-registeration.
*/
static int login_self_choosen_userid_already_exists(const char *zUserID){
  int rc = db_exists(
    "SELECT 1 FROM user WHERE login=%Q "
    "UNION ALL "
    "SELECT 1 FROM event WHERE user=%Q OR euser=%Q",
    zUserID, zUserID, zUserID
  );
  return rc;
}

/*
** Check an email address and confirm that it is valid for self-registration.
** The email address is known already to be well-formed.  Return true
** if the email address is on the allowed list.
**
** The default behavior is that any valid email address is accepted.
** But if the "auth-sub-email" setting exists and is not empty, then
** it is a comma-separated list of GLOB patterns for email addresses
** that are authorized to self-register.
*/
int authorized_subscription_email(const char *zEAddr){
  char *zGlob = db_get("auth-sub-email",0);
  Glob *pGlob;
  char *zAddr;
  int rc;

  if( zGlob==0 || zGlob[0]==0 ) return 1;
  zGlob = fossil_strtolwr(fossil_strdup(zGlob));
  pGlob = glob_create(zGlob);
  fossil_free(zGlob);

  zAddr = fossil_strtolwr(fossil_strdup(zEAddr));
  rc = glob_match(pGlob, zAddr);
  fossil_free(zAddr);
  glob_free(pGlob);
  return rc!=0;
}

/*
** WEBPAGE: register
**
** Page to allow users to self-register.  The "self-register" setting
** must be enabled for this page to operate.
*/
void register_page(void){
  const char *zUserID, *zPasswd, *zConfirm, *zEAddr;
  const char *zDName;
  unsigned int uSeed;
  const char *zDecoded;

  int iErrLine = -1;
  const char *zErr = 0;
  int captchaIsCorrect = 0; /* True on a correct captcha */
  char *zCaptcha = "";      /* Value of the captcha text */
  char *zPerms;             /* Permissions for the default user */
  int canDoAlerts = 0;      /* True if receiving email alerts is possible */
  int doAlerts = 0;         /* True if subscription is wanted too */
  if( !db_get_boolean("self-register", 0) ){
    style_header("Registration not possible");
    @ <p>This project does not allow user self-registration. Please contact the
    @ project administrator to obtain an account.</p>
    style_footer();
    return;
  }
  zPerms = db_get("default-perms", "u");

  /* Prompt the user for email alerts if this repository is configured for
  ** email alerts and if the default permissions include "7" */
  canDoAlerts = alert_tables_exist() && db_int(0,
    "SELECT fullcap(%Q) GLOB '*7*'", zPerms
  );
  doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0;

  zUserID = PDT("u","");
  zPasswd = PDT("p","");
  zConfirm = PDT("cp","");
  zEAddr = PDT("ea","");
  zDName = PDT("dn","");

  /* Verify user imputs */
  if( P("new")==0 || !cgi_csrf_safe(1) ){
    /* This is not a valid form submission.  Fall through into
    ** the form display */
  }else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
    iErrLine = 6;
    zErr = "Incorrect CAPTCHA";
  }else if( strlen(zUserID)<6 ){
    iErrLine = 1;
    zErr = "User ID too short. Must be at least 6 characters.";
  }else if( sqlite3_strglob("*[^-a-zA-Z0-9_.]*",zUserID)==0 ){
    iErrLine = 1;
    zErr = "User ID may not contain spaces or special characters.";
  }else if( zDName[0]==0 ){
    iErrLine = 2;
    zErr = "Required";
  }else if( zEAddr[0]==0 ){
    iErrLine = 3;
    zErr = "Required";
  }else if( email_address_is_valid(zEAddr,0)==0 ){
    iErrLine = 3;
    zErr = "Not a valid email address";
  }else if( authorized_subscription_email(zEAddr)==0 ){
    iErrLine = 3;
    zErr = "Not an authorized email address";
  }else if( strlen(zPasswd)<6 ){
    iErrLine = 4;
    zErr = "Password must be at least 6 characters long";
  }else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
    iErrLine = 5;
    zErr = "Passwords do not match";
  }else if( login_self_choosen_userid_already_exists(zUserID) ){
    iErrLine = 1;
    zErr = "This User ID is already taken. Choose something different.";
  }else if(
      /* If the email is found anywhere in USER.INFO... */
      db_exists("SELECT 1 FROM user WHERE info LIKE '%%%q%%'", zEAddr)
    ||
      /* Or if the email is a verify subscriber email with an associated
      ** user... */
      db_exists(
        "SELECT 1 FROM subscriber WHERE semail=%Q AND suname IS NOT NULL"
        " AND sverified",zEAddr)
   ){
    iErrLine = 3;
    zErr = "This email address is already claimed by another user";
  }else{
    /* If all of the tests above have passed, that means that the submitted
    ** form contains valid data and we can proceed to create the new login */
    Blob sql;
    int uid;
    char *zPass = sha1_shared_secret(zPasswd, zUserID, 0);
    const char *zStartPerms = zPerms;
    if( db_get_boolean("selfreg-verify",0) ){
      /* If email verification is required for self-registration, initalize
      ** the new user capabilities to just "7" (Sign up for email).  The
      ** full "default-perms" permissions will be added when they click
      ** the verification link on the email they are sent. */
      zStartPerms = "7";
    }
    blob_init(&sql, 0, 0);
    blob_append_sql(&sql,
       "INSERT INTO user(login,pw,cap,info,mtime)\n"
       "VALUES(%Q,%Q,%Q,"
       "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())",
       zUserID, zPass, zStartPerms, zDName, zEAddr, g.zIpAddr);
    fossil_free(zPass);
    db_multi_exec("%s", blob_sql_text(&sql));
    uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID);
    login_set_user_cookie(zUserID, uid, NULL);
    if( doAlerts ){
      /* Also make the new user a subscriber. */
      Blob hdr, body;
      AlertSender *pSender;
      sqlite3_int64 id;   /* New subscriber Id */
      const char *zCode;  /* New subscriber code (in hex) */
      const char *zGoto = P("g");
      int nsub = 0;
      char ssub[20];
      CapabilityString *pCap;
      pCap = capability_add(0, zPerms);
      capability_expand(pCap);
      ssub[nsub++] = 'a';
      if( capability_has_any(pCap,"o") ) ssub[nsub++] = 'c';
      if( capability_has_any(pCap,"2") ) ssub[nsub++] = 'f';
      if( capability_has_any(pCap,"r") ) ssub[nsub++] = 't';
      if( capability_has_any(pCap,"j") ) ssub[nsub++] = 'w';
      ssub[nsub] = 0;
      capability_free(pCap);
      /* Also add the user to the subscriber table. */
      db_multi_exec(
        "INSERT INTO subscriber(semail,suname,"
        "  sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)"
        " VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)"
        " ON CONFLICT(semail) DO UPDATE"
        "   SET suname=excluded.suname",
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654



1655

1656
1657
1658
1659
1660
1661
1662
        @ <p>The following internal error was encountered while trying
        @ to send the confirmation email:
        @ <blockquote><pre>
        @ %h(pSender->zErr)
        @ </pre></blockquote>
      }else{
        @ <p>An email has been sent to "%h(zEAddr)". That email contains a
        @ hyperlink that you must click on in order to activate your
        @ subscription.</p>
      }
      alert_sender_free(pSender);
      if( zGoto ){
        @ <p><a href='%h(zGoto)'>Continue</a>
      }
      style_footer();
      return;
    }
    redirect_to_g();
  }

  /* Prepare the captcha. */



  uSeed = captcha_seed();

  zDecoded = captcha_decode(uSeed);
  zCaptcha = captcha_render(zDecoded);

  style_header("Register");
  /* Print out the registration form. */
  form_begin(0, "%R/register");
  if( P("g") ){







|
<












>
>
>
|
>







1658
1659
1660
1661
1662
1663
1664
1665

1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
        @ <p>The following internal error was encountered while trying
        @ to send the confirmation email:
        @ <blockquote><pre>
        @ %h(pSender->zErr)
        @ </pre></blockquote>
      }else{
        @ <p>An email has been sent to "%h(zEAddr)". That email contains a
        @ hyperlink that you must click to activate your account.</p>

      }
      alert_sender_free(pSender);
      if( zGoto ){
        @ <p><a href='%h(zGoto)'>Continue</a>
      }
      style_footer();
      return;
    }
    redirect_to_g();
  }

  /* Prepare the captcha. */
  if( captchaIsCorrect ){
    uSeed = strtoul(P("captchaseed"),0,10);
  }else{
    uSeed = captcha_seed();
  }
  zDecoded = captcha_decode(uSeed);
  zCaptcha = captcha_render(zDecoded);

  style_header("Register");
  /* Print out the registration form. */
  form_begin(0, "%R/register");
  if( P("g") ){
1707
1708
1709
1710
1711
1712
1713
1714



1715
1716
1717
1718
1719
1720
1721
  @   <td><input type="password" name="cp" value="%h(zConfirm)" size="30"></td>
  @ </tr>
  if( iErrLine==5 ){
    @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
  }
  @ <tr>
  @   <td class="form_label" align="right">Captcha:</td>
  @   <td><input type="text" name="captcha" value="" size="30"></td>



  @ </tr>
  if( iErrLine==6 ){
    @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
  }
  @ <tr><td></td>
  @ <td><input type="submit" name="new" value="Register" /></td></tr>
  @ </table>







|
>
>
>







1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
  @   <td><input type="password" name="cp" value="%h(zConfirm)" size="30"></td>
  @ </tr>
  if( iErrLine==5 ){
    @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
  }
  @ <tr>
  @   <td class="form_label" align="right">Captcha:</td>
  @   <td><input type="text" name="captcha" size="30"\
  @ value="%h(captchaIsCorrect?zDecoded:"")" size="30">
  captcha_speakit_button(uSeed, "Speak the captcha text");
  @   </td>
  @ </tr>
  if( iErrLine==6 ){
    @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
  }
  @ <tr><td></td>
  @ <td><input type="submit" name="new" value="Register" /></td></tr>
  @ </table>
Changes to src/main.c.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

/*
** Holds flags for fossil user permissions.
*/
struct FossilUserPerms {
  char Setup;            /* s: use Setup screens on web interface */
  char Admin;            /* a: administrative permission */
  char Delete;           /* d: delete wiki or tickets */
  char Password;         /* p: change password */
  char Query;            /* q: create new reports */
  char Write;            /* i: xfer inbound. check-in */
  char Read;             /* o: xfer outbound. check-out */
  char Hyperlink;        /* h: enable the display of hyperlinks */
  char Clone;            /* g: clone */
  char RdWiki;           /* j: view wiki via web */







<







76
77
78
79
80
81
82

83
84
85
86
87
88
89

/*
** Holds flags for fossil user permissions.
*/
struct FossilUserPerms {
  char Setup;            /* s: use Setup screens on web interface */
  char Admin;            /* a: administrative permission */

  char Password;         /* p: change password */
  char Query;            /* q: create new reports */
  char Write;            /* i: xfer inbound. check-in */
  char Read;             /* o: xfer outbound. check-out */
  char Hyperlink;        /* h: enable the display of hyperlinks */
  char Clone;            /* g: clone */
  char RdWiki;           /* j: view wiki via web */
265
266
267
268
269
270
271
272
273

274
275
276
277
278
279
280
  int nRequest;                  /* Total # of HTTP request */
#ifdef FOSSIL_ENABLE_JSON
  struct FossilJsonBits {
    int isJsonMode;            /* True if running in JSON mode, else
                                  false. This changes how errors are
                                  reported. In JSON mode we try to
                                  always output JSON-form error
                                  responses and always exit() with
                                  code 0 to avoid an HTTP 500 error.

                               */
    int resultCode;            /* used for passing back specific codes
                               ** from /json callbacks. */
    int errorDetailParanoia;   /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
    cson_output_opt outOpt;    /* formatting options for JSON mode. */
    cson_value *authToken;     /* authentication token */
    const char *jsonp;         /* Name of JSONP function wrapper. */







|
|
>







264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  int nRequest;                  /* Total # of HTTP request */
#ifdef FOSSIL_ENABLE_JSON
  struct FossilJsonBits {
    int isJsonMode;            /* True if running in JSON mode, else
                                  false. This changes how errors are
                                  reported. In JSON mode we try to
                                  always output JSON-form error
                                  responses and always (in CGI mode)
                                  exit() with code 0 to avoid an HTTP
                                  500 error.
                               */
    int resultCode;            /* used for passing back specific codes
                               ** from /json callbacks. */
    int errorDetailParanoia;   /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
    cson_output_opt outOpt;    /* formatting options for JSON mode. */
    cson_value *authToken;     /* authentication token */
    const char *jsonp;         /* Name of JSONP function wrapper. */
362
363
364
365
366
367
368



369
370
371
372
373
374
375
  cson_value_free(g.json.gc.v);
  memset(&g.json, 0, sizeof(g.json));
#endif
  free(g.zErrMsg);
  if(g.db){
    db_close(0);
  }



  /*
  ** FIXME: The next two lines cannot always be enabled; however, they
  **        are very useful for tracking down TH1 memory leaks.
  */
  if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){
    if( g.interp ){
      Th_DeleteInterp(g.interp); g.interp = 0;







>
>
>







362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  cson_value_free(g.json.gc.v);
  memset(&g.json, 0, sizeof(g.json));
#endif
  free(g.zErrMsg);
  if(g.db){
    db_close(0);
  }
  manifest_clear_cache();
  content_clear_cache(1);
  rebuild_clear_cache();
  /*
  ** FIXME: The next two lines cannot always be enabled; however, they
  **        are very useful for tracking down TH1 memory leaks.
  */
  if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){
    if( g.interp ){
      Th_DeleteInterp(g.interp); g.interp = 0;
777
778
779
780
781
782
783










784
785
786
787
788
789
790
791
      if( i==g.argc ){
        for(i=1; i<g.argc; i++) zNewArgv[i+1] = g.argv[i];
        nNewArgc = g.argc+1;
        zNewArgv[i+1] = 0;
      }
      g.argc = nNewArgc;
      g.argv = zNewArgv;










    }
    zCmdName = g.argv[1];
  }
#ifndef _WIN32
  /* There is a bug in stunnel4 in which it sometimes starts up client
  ** processes without first opening file descriptor 2 (standard error).
  ** If this happens, and a subsequent open() of a database returns file
  ** descriptor 2, and then an assert() fires and writes on fd 2, that







>
>
>
>
>
>
>
>
>
>
|







780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
      if( i==g.argc ){
        for(i=1; i<g.argc; i++) zNewArgv[i+1] = g.argv[i];
        nNewArgc = g.argc+1;
        zNewArgv[i+1] = 0;
      }
      g.argc = nNewArgc;
      g.argv = zNewArgv;
#if 0
    }else if( g.argc==2 && file_is_repository(g.argv[1]) ){
      char **zNewArgv = fossil_malloc( sizeof(char*)*4 );
      zNewArgv[0] = g.argv[0];
      zNewArgv[1] = "ui";
      zNewArgv[2] = g.argv[1];
      zNewArgv[3] = 0;
      g.argc = 3;
      g.argv = zNewArgv;
#endif
    }   
    zCmdName = g.argv[1];
  }
#ifndef _WIN32
  /* There is a bug in stunnel4 in which it sometimes starts up client
  ** processes without first opening file descriptor 2 (standard error).
  ** If this happens, and a subsequent open() of a database returns file
  ** descriptor 2, and then an assert() fires and writes on fd 2, that
807
808
809
810
811
812
813















814
815
816
817
818
819
820
      fossil_panic("file descriptor 2 is not open. (fd=%d, errno=%d)",
                   fd, x);
    }
  }
#endif
  g.zCmdName = zCmdName;
  rc = dispatch_name_search(zCmdName, CMDFLAG_COMMAND|CMDFLAG_PREFIX, &pCmd);















  if( rc==1 ){
#ifdef FOSSIL_ENABLE_TH1_HOOKS
    if( !g.isHTTP && !g.fNoThHook ){
      rc = Th_CommandHook(zCmdName, 0);
    }else{
      rc = TH_OK;
    }







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







820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
      fossil_panic("file descriptor 2 is not open. (fd=%d, errno=%d)",
                   fd, x);
    }
  }
#endif
  g.zCmdName = zCmdName;
  rc = dispatch_name_search(zCmdName, CMDFLAG_COMMAND|CMDFLAG_PREFIX, &pCmd);
  if( rc==1 && g.argc==2 && file_is_repository(g.argv[1]) ){
    /* If the command-line is "fossil ABC" and "ABC" is no a valid command,
    ** but "ABC" is the name of a repository file, make the command be
    ** "fossil ui ABC" instead.
    */
    char **zNewArgv = fossil_malloc( sizeof(char*)*4 );
    zNewArgv[0] = g.argv[0];
    zNewArgv[1] = "ui";
    zNewArgv[2] = g.argv[1];
    zNewArgv[3] = 0;
    g.argc = 3;
    g.argv = zNewArgv;
    g.zCmdName = zCmdName = "ui";
    rc = dispatch_name_search(zCmdName, CMDFLAG_COMMAND|CMDFLAG_PREFIX, &pCmd);
  }
  if( rc==1 ){
#ifdef FOSSIL_ENABLE_TH1_HOOKS
    if( !g.isHTTP && !g.fNoThHook ){
      rc = Th_CommandHook(zCmdName, 0);
    }else{
      rc = TH_OK;
    }
838
839
840
841
842
843
844







845
846
847
848
849
850
851
    dispatch_matching_names(zCmdName, &couldbe);
    fossil_print("%s: ambiguous command prefix: %s\n"
                 "%s: could be any of:%s\n"
                 "%s: use \"help\" for more information\n",
                 g.argv[0], zCmdName, g.argv[0], blob_str(&couldbe), g.argv[0]);
    fossil_exit(1);
  }







  atexit( fossil_atexit );
#ifdef FOSSIL_ENABLE_TH1_HOOKS
  /*
  ** The TH1 return codes from the hook will be handled as follows:
  **
  ** TH_OK: The xFunc() and the TH1 notification will both be executed.
  **







>
>
>
>
>
>
>







866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
    dispatch_matching_names(zCmdName, &couldbe);
    fossil_print("%s: ambiguous command prefix: %s\n"
                 "%s: could be any of:%s\n"
                 "%s: use \"help\" for more information\n",
                 g.argv[0], zCmdName, g.argv[0], blob_str(&couldbe), g.argv[0]);
    fossil_exit(1);
  }
#ifdef FOSSIL_ENABLE_JSON
  else if( rc==0 && strcmp("json",pCmd->zName)==0 ){
    g.json.isJsonMode = 1;
  }else{
    assert(!g.json.isJsonMode && "JSON-mode misconfiguration.");
  }
#endif
  atexit( fossil_atexit );
#ifdef FOSSIL_ENABLE_TH1_HOOKS
  /*
  ** The TH1 return codes from the hook will be handled as follows:
  **
  ** TH_OK: The xFunc() and the TH1 notification will both be executed.
  **
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
}

/*
** This function populates a blob with version information.  It is used by
** the "version" command and "test-version" web page.  It assumes the blob
** passed to it is uninitialized; otherwise, it will leak memory.
*/
static void get_version_blob(
  Blob *pOut,                 /* Write the manifest here */
  int bVerbose                /* Non-zero for full information. */
){
#if defined(FOSSIL_ENABLE_TCL)
  int rc;
  const char *zRc;
#endif







|







1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
}

/*
** This function populates a blob with version information.  It is used by
** the "version" command and "test-version" web page.  It assumes the blob
** passed to it is uninitialized; otherwise, it will leak memory.
*/
void fossil_version_blob(
  Blob *pOut,                 /* Write the manifest here */
  int bVerbose                /* Non-zero for full information. */
){
#if defined(FOSSIL_ENABLE_TCL)
  int rc;
  const char *zRc;
#endif
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
*/
void version_cmd(void){
  Blob versionInfo;
  int verboseFlag = find_option("verbose","v",0)!=0;

  /* We should be done with options.. */
  verify_all_options();
  get_version_blob(&versionInfo, verboseFlag);
  fossil_print("%s", blob_str(&versionInfo));
}


/*
** WEBPAGE: version
**







|







1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
*/
void version_cmd(void){
  Blob versionInfo;
  int verboseFlag = find_option("verbose","v",0)!=0;

  /* We should be done with options.. */
  verify_all_options();
  fossil_version_blob(&versionInfo, verboseFlag);
  fossil_print("%s", blob_str(&versionInfo));
}


/*
** WEBPAGE: version
**
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
  int verboseFlag;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  verboseFlag = PD("verbose", 0) != 0;
  style_header("Version Information");
  style_submenu_element("Stat", "stat");
  get_version_blob(&versionInfo, verboseFlag);
  @ <pre>
  @ %h(blob_str(&versionInfo))
  @ </pre>
  style_footer();
}









|







1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
  int verboseFlag;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  verboseFlag = PD("verbose", 0) != 0;
  style_header("Version Information");
  style_submenu_element("Stat", "stat");
  fossil_version_blob(&versionInfo, verboseFlag);
  @ <pre>
  @ %h(blob_str(&versionInfo))
  @ </pre>
  style_footer();
}


1505
1506
1507
1508
1509
1510
1511













1512

1513
1514
1515
1516
1517
1518
1519

  /* Handle universal query parameters */
  if( PB("utc") ){
    g.fTimeFormat = 1;
  }else if( PB("localtime") ){
    g.fTimeFormat = 2;
  }















  /* If the repository has not been opened already, then find the
  ** repository based on the first element of PATH_INFO and open it.
  */
  if( !g.repositoryOpen ){
    char *zRepo;               /* Candidate repository name */
    char *zToFree = 0;         /* Malloced memory that needs to be freed */
    const char *zCleanRepo;    /* zRepo with surplus leading "/" removed */







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







1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568

  /* Handle universal query parameters */
  if( PB("utc") ){
    g.fTimeFormat = 1;
  }else if( PB("localtime") ){
    g.fTimeFormat = 2;
  }
#ifdef FOSSIL_ENABLE_JSON
  /*
  ** Ensure that JSON mode is set up if we're visiting /json, to allow
  ** us to customize some following behaviour (error handling and only
  ** process JSON-mode POST data if we're actually in a /json
  ** page). This is normally set up before this routine is called, but
  ** it looks like the ssh_request_loop() approach to dispatching
  ** might bypass that.
  */
  if( g.json.isJsonMode==0 && zPathInfo!=0
      && 0==strncmp("/json",zPathInfo,5)
      && (zPathInfo[5]==0 || zPathInfo[5]=='/')){
    g.json.isJsonMode = 1;
  }
#endif
  /* If the repository has not been opened already, then find the
  ** repository based on the first element of PATH_INFO and open it.
  */
  if( !g.repositoryOpen ){
    char *zRepo;               /* Candidate repository name */
    char *zToFree = 0;         /* Malloced memory that needs to be freed */
    const char *zCleanRepo;    /* zRepo with surplus leading "/" removed */
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
          return;
        }
        zRepo[j] = '.';
      }

      /* If we reach this point, it means that the search of the PATH_INFO
      ** string is finished.  Either zRepo contains the name of the
      ** repository to be used, or else no repository could be found an
      ** some kind of error response is required.
      */
      if( szFile<1024 ){
        set_base_url(0);
        if( (zPathInfo[0]==0 || strcmp(zPathInfo,"/")==0)
                  && allowRepoList
                  && repo_list_page() ){







|







1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
          return;
        }
        zRepo[j] = '.';
      }

      /* If we reach this point, it means that the search of the PATH_INFO
      ** string is finished.  Either zRepo contains the name of the
      ** repository to be used, or else no repository could be found and
      ** some kind of error response is required.
      */
      if( szFile<1024 ){
        set_base_url(0);
        if( (zPathInfo[0]==0 || strcmp(zPathInfo,"/")==0)
                  && allowRepoList
                  && repo_list_page() ){
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
#endif
          @ <html><head>
          @ <meta name="viewport" \
          @ content="width=device-width, initial-scale=1.0">
          @ </head><body>
          @ <h1>Not Found</h1>
          @ </body>
          cgi_set_status(404, "not found");
          cgi_reply();
        }
        return;
      }
      break;
    }








|







1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
#endif
          @ <html><head>
          @ <meta name="viewport" \
          @ content="width=device-width, initial-scale=1.0">
          @ </head><body>
          @ <h1>Not Found</h1>
          @ </body>
          cgi_set_status(404, "Not Found");
          cgi_reply();
        }
        return;
      }
      break;
    }

1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
      zPath[i] = 0;
      g.zExtra = &zPath[i+1];
    }else{
      g.zExtra = 0;
    }
    break;
  }
#ifdef FOSSIL_ENABLE_JSON
  /*
  ** Workaround to allow us to customize some following behaviour for
  ** JSON mode.  The problem is, we don't always know if we're in JSON
  ** mode at this point (namely, for GET mode we don't know but POST
  ** we do), so we snoop g.zPath and cheat a bit.
  */
  if( !g.json.isJsonMode && g.zPath && (0==strncmp("json",g.zPath,4)) ){
    g.json.isJsonMode = 1;
  }
#endif
  if( g.zExtra ){
    /* CGI parameters get this treatment elsewhere, but places like getfile
    ** will use g.zExtra directly.
    ** Reminder: the login mechanism uses 'name' differently, and may
    ** eventually have a problem/collision with this.
    **
    ** Disabled by stephan when running in JSON mode because this







<
<
<
<
<
<
<
<
<
<
<







1816
1817
1818
1819
1820
1821
1822











1823
1824
1825
1826
1827
1828
1829
      zPath[i] = 0;
      g.zExtra = &zPath[i+1];
    }else{
      g.zExtra = 0;
    }
    break;
  }











  if( g.zExtra ){
    /* CGI parameters get this treatment elsewhere, but places like getfile
    ** will use g.zExtra directly.
    ** Reminder: the login mechanism uses 'name' differently, and may
    ** eventually have a problem/collision with this.
    **
    ** Disabled by stephan when running in JSON mode because this
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
  /* Initialize the CGI environment. */
  g.httpOut = stdout;
  g.httpIn = stdin;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.cgiOutput = 1;
  fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
  /* Read and parse the CGI control file. */
  if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
    zFile = g.argv[2];
  }else if( g.argc>=2 ){
    zFile = g.argv[1];
  }else{
    cgi_panic("No CGI control file specified");
  }







|







2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
  /* Initialize the CGI environment. */
  g.httpOut = stdout;
  g.httpIn = stdin;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.cgiOutput = 1;
  fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
  /* Find the name of the CGI control file */
  if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
    zFile = g.argv[2];
  }else if( g.argc>=2 ){
    zFile = g.argv[1];
  }else{
    cgi_panic("No CGI control file specified");
  }
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
      */
      blob_token(&line,&value2);
      fossil_setenv(blob_str(&value), blob_str(&value2));
      blob_reset(&value);
      blob_reset(&value2);
      continue;
    }
    if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
      /* debug: FILENAME
      **
      ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
      ** into FILENAME.
      */
      g.fDebug = fossil_fopen(blob_str(&value), "ab");
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
      /* errorlog: FILENAME
      **
      ** Causes messages from warnings, errors, and panics to be appended
      ** to FILENAME.
      */
      g.zErrlog = mprintf("%s", blob_str(&value));







<
<
<
<
<
<
<
<
<
<







2183
2184
2185
2186
2187
2188
2189










2190
2191
2192
2193
2194
2195
2196
      */
      blob_token(&line,&value2);
      fossil_setenv(blob_str(&value), blob_str(&value2));
      blob_reset(&value);
      blob_reset(&value2);
      continue;
    }










    if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
      /* errorlog: FILENAME
      **
      ** Causes messages from warnings, errors, and panics to be appended
      ** to FILENAME.
      */
      g.zErrlog = mprintf("%s", blob_str(&value));
2204
2205
2206
2207
2208
2209
2210















2211
2212
2213
2214
2215
2216
2217
      ** name of the subdirectory under the skins/ directory that holds
      ** the elements of the built-in skin.  If LABEL does not match,
      ** this directive is a silent no-op.
      */
      skin_use_alternative(blob_str(&value));
      blob_reset(&value);
      continue;















    }
  }
  blob_reset(&config);
  if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
    cgi_panic("Unable to find or open the project repository");
  }
  cgi_init();







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







2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
      ** name of the subdirectory under the skins/ directory that holds
      ** the elements of the built-in skin.  If LABEL does not match,
      ** this directive is a silent no-op.
      */
      skin_use_alternative(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){
      /* cgi-debug: FILENAME
      **
      ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
      ** into FILENAME.  Useful for debugging CGI configuration problems.
      */
      char *zNow = cgi_iso8601_datestamp();
      cgi_load_environment();
      g.fDebug = fossil_fopen(blob_str(&value), "ab");
      blob_reset(&value);
      cgi_debug("-------- BEGIN cgi at %s --------\n", zNow);
      fossil_free(zNow);
      cgi_print_all(1,2);
      continue;
    }
  }
  blob_reset(&config);
  if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
    cgi_panic("Unable to find or open the project repository");
  }
  cgi_init();
2478
2479
2480
2481
2482
2483
2484

2485
2486
2487
2488

2489
2490
2491


2492



2493
2494
2495
2496
2497
2498
2499
**
** COMMAND: test-http
**
** Works like the http command but gives setup permission to all users.
**
** Options:
**   --th-trace          trace TH1 execution (for debugging purposes)

**
*/
void cmd_test_http(void){
  const char *zIpAddr;    /* IP address of remote client */


  Th_InitTraceLog();
  login_set_capabilities("sx", 0);


  g.useLocalauth = 1;



  g.httpIn = stdin;
  g.httpOut = stdout;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.zExtRoot = find_option("extroot",0,1);
  find_server_repository(2, 0);
  g.cgiOutput = 1;







>




>


<
>
>
|
>
>
>







2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535

2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
**
** COMMAND: test-http
**
** Works like the http command but gives setup permission to all users.
**
** Options:
**   --th-trace          trace TH1 execution (for debugging purposes)
**   --usercap   CAP     user capability string.  (Default: "sx")
**
*/
void cmd_test_http(void){
  const char *zIpAddr;    /* IP address of remote client */
  const char *zUserCap;

  Th_InitTraceLog();

  zUserCap = find_option("usercap",0,1);
  if( zUserCap==0 ){
    g.useLocalauth = 1;
    zUserCap = "sx";
  }
  login_set_capabilities(zUserCap, 0);
  g.httpIn = stdin;
  g.httpOut = stdout;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.zExtRoot = find_option("extroot",0,1);
  find_server_repository(2, 0);
  g.cgiOutput = 1;
Changes to src/main.mk.
16
17
18
19
20
21
22

23
24
25
26
27
28
29
TESTFLAGS := -quiet

SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/alerts.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/attach.c \

  $(SRCDIR)/backoffice.c \
  $(SRCDIR)/bag.c \
  $(SRCDIR)/bisect.c \
  $(SRCDIR)/blob.c \
  $(SRCDIR)/branch.c \
  $(SRCDIR)/browse.c \
  $(SRCDIR)/builtin.c \







>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
TESTFLAGS := -quiet

SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/alerts.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/attach.c \
  $(SRCDIR)/backlink.c \
  $(SRCDIR)/backoffice.c \
  $(SRCDIR)/bag.c \
  $(SRCDIR)/bisect.c \
  $(SRCDIR)/blob.c \
  $(SRCDIR)/branch.c \
  $(SRCDIR)/browse.c \
  $(SRCDIR)/builtin.c \
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
  $(SRCDIR)/../skins/rounded1/details.txt \
  $(SRCDIR)/../skins/rounded1/footer.txt \
  $(SRCDIR)/../skins/rounded1/header.txt \
  $(SRCDIR)/../skins/xekri/css.txt \
  $(SRCDIR)/../skins/xekri/details.txt \
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \

  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
















  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/whistory.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/alerts_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \

  $(OBJDIR)/backoffice_.c \
  $(OBJDIR)/bag_.c \
  $(OBJDIR)/bisect_.c \
  $(OBJDIR)/blob_.c \
  $(OBJDIR)/branch_.c \
  $(OBJDIR)/browse_.c \
  $(OBJDIR)/builtin_.c \







>













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










>







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
  $(SRCDIR)/../skins/rounded1/details.txt \
  $(SRCDIR)/../skins/rounded1/footer.txt \
  $(SRCDIR)/../skins/rounded1/header.txt \
  $(SRCDIR)/../skins/xekri/css.txt \
  $(SRCDIR)/../skins/xekri/details.txt \
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \
  $(SRCDIR)/accordion.js \
  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \
  $(SRCDIR)/sounds/4.wav \
  $(SRCDIR)/sounds/5.wav \
  $(SRCDIR)/sounds/6.wav \
  $(SRCDIR)/sounds/7.wav \
  $(SRCDIR)/sounds/8.wav \
  $(SRCDIR)/sounds/9.wav \
  $(SRCDIR)/sounds/a.wav \
  $(SRCDIR)/sounds/b.wav \
  $(SRCDIR)/sounds/c.wav \
  $(SRCDIR)/sounds/d.wav \
  $(SRCDIR)/sounds/e.wav \
  $(SRCDIR)/sounds/f.wav \
  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/whistory.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/alerts_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \
  $(OBJDIR)/backlink_.c \
  $(OBJDIR)/backoffice_.c \
  $(OBJDIR)/bag_.c \
  $(OBJDIR)/bisect_.c \
  $(OBJDIR)/blob_.c \
  $(OBJDIR)/branch_.c \
  $(OBJDIR)/browse_.c \
  $(OBJDIR)/builtin_.c \
373
374
375
376
377
378
379

380
381
382
383
384
385
386
  $(OBJDIR)/zip_.c

OBJ = \
 $(OBJDIR)/add.o \
 $(OBJDIR)/alerts.o \
 $(OBJDIR)/allrepo.o \
 $(OBJDIR)/attach.o \

 $(OBJDIR)/backoffice.o \
 $(OBJDIR)/bag.o \
 $(OBJDIR)/bisect.o \
 $(OBJDIR)/blob.o \
 $(OBJDIR)/branch.o \
 $(OBJDIR)/browse.o \
 $(OBJDIR)/builtin.o \







>







392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  $(OBJDIR)/zip_.c

OBJ = \
 $(OBJDIR)/add.o \
 $(OBJDIR)/alerts.o \
 $(OBJDIR)/allrepo.o \
 $(OBJDIR)/attach.o \
 $(OBJDIR)/backlink.o \
 $(OBJDIR)/backoffice.o \
 $(OBJDIR)/bag.o \
 $(OBJDIR)/bisect.o \
 $(OBJDIR)/blob.o \
 $(OBJDIR)/branch.o \
 $(OBJDIR)/browse.o \
 $(OBJDIR)/builtin.o \
588
589
590
591
592
593
594
595

596
597
598
599
600
601
602
                 -DSQLITE_ENABLE_FTS4 \
                 -DSQLITE_ENABLE_DBSTAT_VTAB \
                 -DSQLITE_ENABLE_JSON1 \
                 -DSQLITE_ENABLE_FTS5 \
                 -DSQLITE_ENABLE_STMTVTAB \
                 -DSQLITE_HAVE_ZLIB \
                 -DSQLITE_INTROSPECTION_PRAGMAS \
                 -DSQLITE_ENABLE_DBPAGE_VTAB


# Setup the options used to compile the included SQLite shell.
SHELL_OPTIONS = -DNDEBUG=1 \
                -DSQLITE_DQS=0 \
                -DSQLITE_THREADSAFE=0 \
                -DSQLITE_DEFAULT_MEMSTATUS=0 \
                -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \







|
>







608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
                 -DSQLITE_ENABLE_FTS4 \
                 -DSQLITE_ENABLE_DBSTAT_VTAB \
                 -DSQLITE_ENABLE_JSON1 \
                 -DSQLITE_ENABLE_FTS5 \
                 -DSQLITE_ENABLE_STMTVTAB \
                 -DSQLITE_HAVE_ZLIB \
                 -DSQLITE_INTROSPECTION_PRAGMAS \
                 -DSQLITE_ENABLE_DBPAGE_VTAB \
                 -DSQLITE_TRUSTED_SCHEMA=0

# Setup the options used to compile the included SQLite shell.
SHELL_OPTIONS = -DNDEBUG=1 \
                -DSQLITE_DQS=0 \
                -DSQLITE_THREADSAFE=0 \
                -DSQLITE_DEFAULT_MEMSTATUS=0 \
                -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
616
617
618
619
620
621
622

623
624
625
626
627
628
629
                -DSQLITE_ENABLE_DBSTAT_VTAB \
                -DSQLITE_ENABLE_JSON1 \
                -DSQLITE_ENABLE_FTS5 \
                -DSQLITE_ENABLE_STMTVTAB \
                -DSQLITE_HAVE_ZLIB \
                -DSQLITE_INTROSPECTION_PRAGMAS \
                -DSQLITE_ENABLE_DBPAGE_VTAB \

                -Dmain=sqlite3_shell \
                -DSQLITE_SHELL_IS_UTF8=1 \
                -DSQLITE_OMIT_LOAD_EXTENSION=1 \
                -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
                -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
                -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc








>







637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
                -DSQLITE_ENABLE_DBSTAT_VTAB \
                -DSQLITE_ENABLE_JSON1 \
                -DSQLITE_ENABLE_FTS5 \
                -DSQLITE_ENABLE_STMTVTAB \
                -DSQLITE_HAVE_ZLIB \
                -DSQLITE_INTROSPECTION_PRAGMAS \
                -DSQLITE_ENABLE_DBPAGE_VTAB \
                -DSQLITE_TRUSTED_SCHEMA=0 \
                -Dmain=sqlite3_shell \
                -DSQLITE_SHELL_IS_UTF8=1 \
                -DSQLITE_OMIT_LOAD_EXTENSION=1 \
                -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
                -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
                -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc

707
708
709
710
711
712
713

714
715
716
717
718
719
720
	$(OBJDIR)/mkbuiltin --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@

$(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
	$(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
	$(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \
	$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
	$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \

	$(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \
	$(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \
	$(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \
	$(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \
	$(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \
	$(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \
	$(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \







>







729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
	$(OBJDIR)/mkbuiltin --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@

$(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
	$(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
	$(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \
	$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
	$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
	$(OBJDIR)/backlink_.c:$(OBJDIR)/backlink.h \
	$(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \
	$(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \
	$(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \
	$(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \
	$(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \
	$(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \
	$(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \
880
881
882
883
884
885
886








887
888
889
890
891
892
893
$(OBJDIR)/attach_.c:	$(SRCDIR)/attach.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/attach.c >$@

$(OBJDIR)/attach.o:	$(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c

$(OBJDIR)/attach.h:	$(OBJDIR)/headers









$(OBJDIR)/backoffice_.c:	$(SRCDIR)/backoffice.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/backoffice.c >$@

$(OBJDIR)/backoffice.o:	$(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c








>
>
>
>
>
>
>
>







903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
$(OBJDIR)/attach_.c:	$(SRCDIR)/attach.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/attach.c >$@

$(OBJDIR)/attach.o:	$(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c

$(OBJDIR)/attach.h:	$(OBJDIR)/headers

$(OBJDIR)/backlink_.c:	$(SRCDIR)/backlink.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/backlink.c >$@

$(OBJDIR)/backlink.o:	$(OBJDIR)/backlink_.c $(OBJDIR)/backlink.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backlink.o -c $(OBJDIR)/backlink_.c

$(OBJDIR)/backlink.h:	$(OBJDIR)/headers

$(OBJDIR)/backoffice_.c:	$(SRCDIR)/backoffice.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/backoffice.c >$@

$(OBJDIR)/backoffice.o:	$(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c

Changes to src/makeheaders.html.
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
Finally, makeheaders also includes a &#8220;<code>-doc</code>&#8221; option.
This command line option prevents makeheaders from generating any
headers at all.
Instead, makeheaders will write to standard output
information about every definition and declaration that it encounters
in its scan of source files.
The information output includes the type of the definition or
declaration and any comment that preceeds the definition or
declaration.
The output is in a format that can be easily parsed, and is
intended to be read by another program that will generate
documentation about the program.
We'll talk more about this feature later.
</p>








|







341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
Finally, makeheaders also includes a &#8220;<code>-doc</code>&#8221; option.
This command line option prevents makeheaders from generating any
headers at all.
Instead, makeheaders will write to standard output
information about every definition and declaration that it encounters
in its scan of source files.
The information output includes the type of the definition or
declaration and any comment that precedes the definition or
declaration.
The output is in a format that can be easily parsed, and is
intended to be read by another program that will generate
documentation about the program.
We'll talk more about this feature later.
</p>

397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
named &#8220;<code>alpha.h</code>&#8221;.
For that reason, you don't want to use that name for
any of the .h files you write since that will prevent makeheaders
from generating the .h file automatically.
</p>

<p>
The structure of a .c file intented for use with makeheaders is very
simple.
All you have to do is add a single &#8220;<code>#include</code>&#8221; to the
top of the file that sources the header file that makeheaders will generate.
Hence, the beginning of a source file named &#8220;<code>alpha.c</code>&#8221;
might look something like this:
</p>








|







397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
named &#8220;<code>alpha.h</code>&#8221;.
For that reason, you don't want to use that name for
any of the .h files you write since that will prevent makeheaders
from generating the .h file automatically.
</p>

<p>
The structure of a .c file intended for use with makeheaders is very
simple.
All you have to do is add a single &#8220;<code>#include</code>&#8221; to the
top of the file that sources the header file that makeheaders will generate.
Hence, the beginning of a source file named &#8220;<code>alpha.c</code>&#8221;
might look something like this:
</p>

589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
<a name="H0009"></a>
<h3>3.3 How To Avoid Having To Write Any Header Files</h3>

<p>
In my experience, large projects work better if all of the manually
written code is placed in .c files and all .h files are generated
automatically.
This is slightly different for the traditional C method of placing
the interface in .h files and the implementation in .c files, but
it is a refreshing change that brings a noticable improvement to the
coding experience.
Others, I believe, share this view since I've
noticed recent languages (ex: java, tcl, perl, awk) tend to
support the one-file approach to coding as the only option.
</p>

<p>







|

|







589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
<a name="H0009"></a>
<h3>3.3 How To Avoid Having To Write Any Header Files</h3>

<p>
In my experience, large projects work better if all of the manually
written code is placed in .c files and all .h files are generated
automatically.
This is slightly different from the traditional C method of placing
the interface in .h files and the implementation in .c files, but
it is a refreshing change that brings a noticeable improvement to the
coding experience.
Others, I believe, share this view since I've
noticed recent languages (ex: java, tcl, perl, awk) tend to
support the one-file approach to coding as the only option.
</p>

<p>
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
it were a .h file by enclosing that part of the .c file within:
<pre>
   #if INTERFACE
   #endif
</pre>
Thus any structure definitions that appear after the
&#8220;<code>#if INTERFACE</code>&#8221; but before the corresponding
&#8220;<code>#endif</code>&#8221; are eligable to be copied into the
automatically generated
.h files of other .c files.
</p>

<p>
If you use the &#8220;<code>#if INTERFACE</code>&#8221; mechanism in a .c file,
then the generated header for that .c file will contain a line







|







617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
it were a .h file by enclosing that part of the .c file within:
<pre>
   #if INTERFACE
   #endif
</pre>
Thus any structure definitions that appear after the
&#8220;<code>#if INTERFACE</code>&#8221; but before the corresponding
&#8220;<code>#endif</code>&#8221; are eligible to be copied into the
automatically generated
.h files of other .c files.
</p>

<p>
If you use the &#8220;<code>#if INTERFACE</code>&#8221; mechanism in a .c file,
then the generated header for that .c file will contain a line
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
</p>

<p>
That isn't the complete truth, actually.
The semantics of C are such that once an object becomes visible
outside of a single source file, it is also visible to any user
of the library that is made from the source file.
Makeheaders can not prevent outsiders for using non-exported resources,
but it can discourage the practice by refusing to provide prototypes
and declarations for the services it does not want to export.
Thus the only real effect of the making an object exportable is
to include it in the output makeheaders generates when it is run
using the -H command line option.
This is not a perfect solution, but it works well in practice.
</p>







|







682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
</p>

<p>
That isn't the complete truth, actually.
The semantics of C are such that once an object becomes visible
outside of a single source file, it is also visible to any user
of the library that is made from the source file.
Makeheaders can not prevent outsiders from using non-exported resources,
but it can discourage the practice by refusing to provide prototypes
and declarations for the services it does not want to export.
Thus the only real effect of the making an object exportable is
to include it in the output makeheaders generates when it is run
using the -H command line option.
This is not a perfect solution, but it works well in practice.
</p>
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
  v1 = 0;
}
</pre></blockquote>

<p>
The first form is preferred because only a single declaration of
the constructor is required.  The second form requires two declarations,
one in the class definition and one on the defintion of the constructor.
</p>

<h4>3.6.1 C++ Limitations</h4>

<p>
Makeheaders does not understand more recent
C++ syntax such as templates and namespaces.







|







866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
  v1 = 0;
}
</pre></blockquote>

<p>
The first form is preferred because only a single declaration of
the constructor is required.  The second form requires two declarations,
one in the class definition and one on the definition of the constructor.
</p>

<h4>3.6.1 C++ Limitations</h4>

<p>
Makeheaders does not understand more recent
C++ syntax such as templates and namespaces.
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
<ul>
<li> The name of the object.
<li> The type of the object.  (Structure, typedef, macro, etc.)
<li> Flags to indicate if the declaration is exported (contained within
     an EXPORT_INTERFACE block) or local (contained with LOCAL_INTERFACE).
<li> A flag to indicate if the object is declared in a C++ file.
<li> The name of the file in which the object was declared.
<li> The complete text of any block comment that preceeds the declarations.
<li> If the declaration occurred inside a preprocessor conditional
     (&#8220;<code>#if</code>&#8221;) then the text of that conditional is
     provided.
<li> The complete text of a declaration for the object.
</ul>
The exact output format will not be described here.
It is simple to understand and parse and should be obvious to







|







1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
<ul>
<li> The name of the object.
<li> The type of the object.  (Structure, typedef, macro, etc.)
<li> Flags to indicate if the declaration is exported (contained within
     an EXPORT_INTERFACE block) or local (contained with LOCAL_INTERFACE).
<li> A flag to indicate if the object is declared in a C++ file.
<li> The name of the file in which the object was declared.
<li> The complete text of any block comment that precedes the declarations.
<li> If the declaration occurred inside a preprocessor conditional
     (&#8220;<code>#if</code>&#8221;) then the text of that conditional is
     provided.
<li> The complete text of a declaration for the object.
</ul>
The exact output format will not be described here.
It is simple to understand and parse and should be obvious to
Changes to src/makemake.tcl.
27
28
29
30
31
32
33

34
35
36
37
38
39
40
# files, such as string and BLOB resources.
#
set src {
  add
  alerts
  allrepo
  attach

  backoffice
  bag
  bisect
  blob
  branch
  browse
  builtin







>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# files, such as string and BLOB resources.
#
set src {
  add
  alerts
  allrepo
  attach
  backlink
  backoffice
  bag
  bisect
  blob
  branch
  browse
  builtin
172
173
174
175
176
177
178

179
180
181
182
183
184
185
#
set extra_files {
  diff.tcl
  markdown.md
  wiki.wiki
  *.js
  ../skins/*/*.txt

}

# Options used to compile the included SQLite library.
#
set SQLITE_OPTIONS {
  -DNDEBUG=1
  -DSQLITE_DQS=0







>







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#
set extra_files {
  diff.tcl
  markdown.md
  wiki.wiki
  *.js
  ../skins/*/*.txt
  sounds/*.wav
}

# Options used to compile the included SQLite library.
#
set SQLITE_OPTIONS {
  -DNDEBUG=1
  -DSQLITE_DQS=0
202
203
204
205
206
207
208

209
210
211
212
213
214
215
  -DSQLITE_ENABLE_DBSTAT_VTAB
  -DSQLITE_ENABLE_JSON1
  -DSQLITE_ENABLE_FTS5
  -DSQLITE_ENABLE_STMTVTAB
  -DSQLITE_HAVE_ZLIB
  -DSQLITE_INTROSPECTION_PRAGMAS
  -DSQLITE_ENABLE_DBPAGE_VTAB

}
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4
#lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI
#lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096

# Options used to compile the included SQLite shell.







>







204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  -DSQLITE_ENABLE_DBSTAT_VTAB
  -DSQLITE_ENABLE_JSON1
  -DSQLITE_ENABLE_FTS5
  -DSQLITE_ENABLE_STMTVTAB
  -DSQLITE_HAVE_ZLIB
  -DSQLITE_INTROSPECTION_PRAGMAS
  -DSQLITE_ENABLE_DBPAGE_VTAB
  -DSQLITE_TRUSTED_SCHEMA=0
}
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4
#lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI
#lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096

# Options used to compile the included SQLite shell.
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
endif

#### The directories where the OpenSSL include and library files are located.
#    The recommended usage here is to use the Sysinternals junction tool
#    to create a hard link between an "openssl-1.x" sub-directory of the
#    Fossil source code directory and the target OpenSSL source directory.
#
OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1d
OPENSSLINCDIR = $(OPENSSLDIR)/include
OPENSSLLIBDIR = $(OPENSSLDIR)

#### Either the directory where the Tcl library is installed or the Tcl
#    source code directory resides (depending on the value of the macro
#    FOSSIL_TCL_SOURCE).  If this points to the Tcl install directory,
#    this directory must have "include" and "lib" sub-directories.  If







|







712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
endif

#### The directories where the OpenSSL include and library files are located.
#    The recommended usage here is to use the Sysinternals junction tool
#    to create a hard link between an "openssl-1.x" sub-directory of the
#    Fossil source code directory and the target OpenSSL source directory.
#
OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1g
OPENSSLINCDIR = $(OPENSSLDIR)/include
OPENSSLLIBDIR = $(OPENSSLDIR)

#### Either the directory where the Tcl library is installed or the Tcl
#    source code directory resides (depending on the value of the macro
#    FOSSIL_TCL_SOURCE).  If this points to the Tcl install directory,
#    this directory must have "include" and "lib" sub-directories.  If
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580

# Enable support for the SQLite Encryption Extension?
!ifndef USE_SEE
USE_SEE = 0
!endif

!if $(FOSSIL_ENABLE_SSL)!=0
SSLDIR    = $(B)\compat\openssl-1.1.1d
SSLINCDIR = $(SSLDIR)\include
!if $(FOSSIL_DYNAMIC_BUILD)!=0
SSLLIBDIR = $(SSLDIR)
!else
SSLLIBDIR = $(SSLDIR)
!endif
SSLLFLAGS = /nologo /opt:ref /debug







|







1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583

# Enable support for the SQLite Encryption Extension?
!ifndef USE_SEE
USE_SEE = 0
!endif

!if $(FOSSIL_ENABLE_SSL)!=0
SSLDIR    = $(B)\compat\openssl-1.1.1g
SSLINCDIR = $(SSLDIR)\include
!if $(FOSSIL_DYNAMIC_BUILD)!=0
SSLLIBDIR = $(SSLDIR)
!else
SSLLIBDIR = $(SSLDIR)
!endif
SSLLFLAGS = /nologo /opt:ref /debug
Changes to src/manifest.c.
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
** A parsed manifest or cluster.
*/
struct Manifest {
  Blob content;         /* The original content blob */
  int type;             /* Type of artifact.  One of CFTYPE_xxxxx */
  int rid;              /* The blob-id for this manifest */
  char *zBaseline;      /* Baseline manifest.  The B card. */
  Manifest *pBaseline;  /* The actual baseline manifest */
  char *zComment;       /* Decoded comment.  The C card. */
  double rDate;         /* Date and time from D card.  0.0 if no D card. */
  char *zUser;          /* Name of the user from the U card. */
  char *zRepoCksum;     /* MD5 checksum of the baseline content.  R card. */
  char *zWiki;          /* Text of the wiki page.  W card. */
  char *zWikiTitle;     /* Name of the wiki page. L card. */







|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
** A parsed manifest or cluster.
*/
struct Manifest {
  Blob content;         /* The original content blob */
  int type;             /* Type of artifact.  One of CFTYPE_xxxxx */
  int rid;              /* The blob-id for this manifest */
  const char *zBaseline;/* Baseline manifest.  The B card. */
  Manifest *pBaseline;  /* The actual baseline manifest */
  char *zComment;       /* Decoded comment.  The C card. */
  double rDate;         /* Date and time from D card.  0.0 if no D card. */
  char *zUser;          /* Name of the user from the U card. */
  char *zRepoCksum;     /* MD5 checksum of the baseline content.  R card. */
  char *zWiki;          /* Text of the wiki page.  W card. */
  char *zWikiTitle;     /* Name of the wiki page. L card. */
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
} manifestCardTypes[] = {
  /*                           Allowed          Required    */
  /* CFTYPE_MANIFEST   1 */ { "BCDFNPQRTUZ",   "DZ"          },
                     /* Wants to be "CDUZ" ----^^^^
                     ** but we must limit for historical compatibility */
  /* CFTYPE_CLUSTER    2 */ { "MZ",            "MZ"          },
  /* CFTYPE_CONTROL    3 */ { "DTUZ",          "DTUZ"        },
  /* CFTYPE_WIKI       4 */ { "DLNPUWZ",       "DLUWZ"       },
  /* CFTYPE_TICKET     5 */ { "DJKUZ",         "DJKUZ"       },
  /* CFTYPE_ATTACHMENT 6 */ { "ACDNUZ",        "ADZ"         },
  /* CFTYPE_EVENT      7 */ { "CDENPTUWZ",     "DEWZ"        },
  /* CFTYPE_FORUM      8 */ { "DGHINPUWZ",     "DUWZ"        },
};

/*







|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
} manifestCardTypes[] = {
  /*                           Allowed          Required    */
  /* CFTYPE_MANIFEST   1 */ { "BCDFNPQRTUZ",   "DZ"          },
                     /* Wants to be "CDUZ" ----^^^^
                     ** but we must limit for historical compatibility */
  /* CFTYPE_CLUSTER    2 */ { "MZ",            "MZ"          },
  /* CFTYPE_CONTROL    3 */ { "DTUZ",          "DTUZ"        },
  /* CFTYPE_WIKI       4 */ { "CDLNPUWZ",      "DLUWZ"       },
  /* CFTYPE_TICKET     5 */ { "DJKUZ",         "DJKUZ"       },
  /* CFTYPE_ATTACHMENT 6 */ { "ACDNUZ",        "ADZ"         },
  /* CFTYPE_EVENT      7 */ { "CDENPTUWZ",     "DEWZ"        },
  /* CFTYPE_FORUM      8 */ { "DGHINPUWZ",     "DUWZ"        },
};

/*
316
317
318
319
320
321
322
323

324
325
326
327

328
329
330

331
332
333
334
335
336
337
** checksum.  Return 0 if there is no Z-card.  Return 1 if the Z-card
** exists and is correct.  Return 2 if the Z-card exists and has the wrong
** value.
**
**   0123456789 123456789 123456789 123456789
**   Z aea84f4f863865a8d59d0384e4d2a41c
*/
static int verify_z_card(const char *z, int n){

  if( n<35 ) return 0;
  if( z[n-35]!='Z' || z[n-34]!=' ' ) return 0;
  md5sum_init();
  md5sum_step_text(z, n-35);

  if( memcmp(&z[n-33], md5sum_finish(0), 32)==0 ){
    return 1;
  }else{

    return 2;
  }
}

/*
** A structure used for rapid parsing of the Manifest file
*/







|
>




>
|


>







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
** checksum.  Return 0 if there is no Z-card.  Return 1 if the Z-card
** exists and is correct.  Return 2 if the Z-card exists and has the wrong
** value.
**
**   0123456789 123456789 123456789 123456789
**   Z aea84f4f863865a8d59d0384e4d2a41c
*/
static int verify_z_card(const char *z, int n, Blob *pErr){
  const char *zHash;
  if( n<35 ) return 0;
  if( z[n-35]!='Z' || z[n-34]!=' ' ) return 0;
  md5sum_init();
  md5sum_step_text(z, n-35);
  zHash = md5sum_finish(0);
  if( memcmp(&z[n-33], zHash, 32)==0 ){
    return 1;
  }else{
    blob_appendf(pErr, "incorrect Z-card cksum: expected %.32s", zHash);
    return 2;
  }
}

/*
** A structure used for rapid parsing of the Manifest file
*/
379
380
381
382
383
384
385













386
387
388
389
390
391
392
  return c;
}

/*
** Shorthand for a control-artifact parsing error
*/
#define SYNTAX(T)  {zErr=(T); goto manifest_syntax_error;}














/*
** Parse a blob into a Manifest object.  The Manifest object
** takes over the input blob and will free it when the
** Manifest object is freed.  Zeros are inserted into the blob
** as string terminators so that blob should not be used again.
**







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







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
  return c;
}

/*
** Shorthand for a control-artifact parsing error
*/
#define SYNTAX(T)  {zErr=(T); goto manifest_syntax_error;}

/*
** A cache of manifest IDs which manifest_parse() has seen in this
** session.
*/
static Bag seenManifests =  Bag_INIT;
/*
** Frees all memory owned by the manifest "has-seen" cache.  Intended
** to be called only from the app's atexit() handler.
*/
void manifest_clear_cache(){
  bag_clear(&seenManifests);
}

/*
** Parse a blob into a Manifest object.  The Manifest object
** takes over the input blob and will free it when the
** Manifest object is freed.  Zeros are inserted into the blob
** as string terminators so that blob should not be used again.
**
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
  char *z;
  int n;
  char *zUuid;
  int sz = 0;
  int isRepeat;
  int nSelfTag = 0;     /* Number of T cards referring to this manifest */
  int nSimpleTag = 0;   /* Number of T cards with "+" prefix */
  static Bag seen;
  const char *zErr = 0;
  unsigned int m;
  unsigned int seenCard = 0;   /* Which card types have been seen */
  char zErrBuf[100];           /* Write error messages here */

  if( rid==0 ){
    isRepeat = 1;
  }else if( bag_find(&seen, rid) ){
    isRepeat = 1;
  }else{
    isRepeat = 0;
    bag_insert(&seen, rid);
  }

  /* Every structural artifact ends with a '\n' character.  Exit early
  ** if that is not the case for this artifact.
  */
  if( !isRepeat ) g.parseCnt[0]++;
  z = blob_materialize(pContent);







<







|



|







439
440
441
442
443
444
445

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  char *z;
  int n;
  char *zUuid;
  int sz = 0;
  int isRepeat;
  int nSelfTag = 0;     /* Number of T cards referring to this manifest */
  int nSimpleTag = 0;   /* Number of T cards with "+" prefix */

  const char *zErr = 0;
  unsigned int m;
  unsigned int seenCard = 0;   /* Which card types have been seen */
  char zErrBuf[100];           /* Write error messages here */

  if( rid==0 ){
    isRepeat = 1;
  }else if( bag_find(&seenManifests, rid) ){
    isRepeat = 1;
  }else{
    isRepeat = 0;
    bag_insert(&seenManifests, rid);
  }

  /* Every structural artifact ends with a '\n' character.  Exit early
  ** if that is not the case for this artifact.
  */
  if( !isRepeat ) g.parseCnt[0]++;
  z = blob_materialize(pContent);
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  if( n<10 || z[0]<'A' || z[0]>'Z' || z[1]!=' ' ){
    blob_reset(pContent);
    blob_appendf(pErr, "line 1 not recognized");
    return 0;
  }
  /* Then verify the Z-card.
  */
  if( verify_z_card(z, n)==2 ){
    blob_reset(pContent);
    blob_appendf(pErr, "incorrect Z-card cksum");
    return 0;
  }

  /* Allocate a Manifest object to hold the parsed control artifact.
  */
  p = fossil_malloc( sizeof(*p) );
  memset(p, 0, sizeof(*p));







|

<







479
480
481
482
483
484
485
486
487

488
489
490
491
492
493
494
  if( n<10 || z[0]<'A' || z[0]>'Z' || z[1]!=' ' ){
    blob_reset(pContent);
    blob_appendf(pErr, "line 1 not recognized");
    return 0;
  }
  /* Then verify the Z-card.
  */
  if( verify_z_card(z, n, pErr)==2 ){
    blob_reset(pContent);

    return 0;
  }

  /* Allocate a Manifest object to hold the parsed control artifact.
  */
  p = fossil_malloc( sizeof(*p) );
  memset(p, 0, sizeof(*p));
1139
1140
1141
1142
1143
1144
1145

1146
1147
1148
1149
1150
1151
1152
    blob_copy(&b2, &b);
    blob_zero(&err);
    p = manifest_parse(&b2, 0, &err);
    if( p==0 ) fossil_print("ERROR: %s\n", blob_str(&err));
    blob_reset(&err);
    manifest_destroy(p);
  }

}

/*
** COMMAND: test-parse-all-blobs
**
** Usage: %fossil test-parse-all-blobs [--limit N]
**







>







1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
    blob_copy(&b2, &b);
    blob_zero(&err);
    p = manifest_parse(&b2, 0, &err);
    if( p==0 ) fossil_print("ERROR: %s\n", blob_str(&err));
    blob_reset(&err);
    manifest_destroy(p);
  }
  blob_reset(&b);
}

/*
** COMMAND: test-parse-all-blobs
**
** Usage: %fossil test-parse-all-blobs [--limit N]
**
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
**
** Return the RID of the primary parent.
*/
static int manifest_add_checkin_linkages(
  int rid,                   /* The RID of the check-in */
  Manifest *p,               /* Manifest for this check-in */
  int nParent,               /* Number of parents for this check-in */
  char **azParent            /* hashes for each parent */
){
  int i;
  int parentid = 0;
  char zBaseId[30];    /* Baseline manifest RID for deltas.  "NULL" otherwise */
  Stmt q;

  if( p->zBaseline ){







|







1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
**
** Return the RID of the primary parent.
*/
static int manifest_add_checkin_linkages(
  int rid,                   /* The RID of the check-in */
  Manifest *p,               /* Manifest for this check-in */
  int nParent,               /* Number of parents for this check-in */
  char * const * azParent    /* hashes for each parent */
){
  int i;
  int parentid = 0;
  char zBaseId[30];    /* Baseline manifest RID for deltas.  "NULL" otherwise */
  Stmt q;

  if( p->zBaseline ){
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826











1827
1828
1829
1830
1831
1832
1833
** by the call to manifest_crosslink_end().
*/
void manifest_crosslink_begin(void){
  assert( manifest_crosslink_busy==0 );
  manifest_crosslink_busy = 1;
  db_begin_transaction();
  db_multi_exec(
     "CREATE TEMP TABLE pending_tkt(uuid TEXT UNIQUE);"
     "CREATE TEMP TABLE time_fudge("
     "  mid INTEGER PRIMARY KEY,"    /* The rid of a manifest */
     "  m1 REAL,"                    /* The timestamp on mid */
     "  cid INTEGER,"                /* A child or mid */
     "  m2 REAL"                     /* Timestamp on the child */
     ");"
  );
}












#if INTERFACE
/* Timestamps might be adjusted slightly to ensure that check-ins appear
** on the timeline in chronological order.  This is the maximum amount
** of the adjustment window, in days.
*/
#define AGE_FUDGE_WINDOW      (2.0/86400.0)       /* 2 seconds */







|








>
>
>
>
>
>
>
>
>
>
>







1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
** by the call to manifest_crosslink_end().
*/
void manifest_crosslink_begin(void){
  assert( manifest_crosslink_busy==0 );
  manifest_crosslink_busy = 1;
  db_begin_transaction();
  db_multi_exec(
     "CREATE TEMP TABLE pending_xlink(id TEXT PRIMARY KEY)WITHOUT ROWID;"
     "CREATE TEMP TABLE time_fudge("
     "  mid INTEGER PRIMARY KEY,"    /* The rid of a manifest */
     "  m1 REAL,"                    /* The timestamp on mid */
     "  cid INTEGER,"                /* A child or mid */
     "  m2 REAL"                     /* Timestamp on the child */
     ");"
  );
}

/*
** Add a new entry to the pending_xlink table.
*/
static void add_pending_crosslink(char cType, const char *zId){
  assert( manifest_crosslink_busy==1 );
  db_multi_exec(
    "INSERT OR IGNORE INTO pending_xlink VALUES('%c%q')",
    cType, zId
  );
}

#if INTERFACE
/* Timestamps might be adjusted slightly to ensure that check-ins appear
** on the timeline in chronological order.  This is the maximum amount
** of the adjustment window, in days.
*/
#define AGE_FUDGE_WINDOW      (2.0/86400.0)       /* 2 seconds */
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871





1872
1873
1874



1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
  );
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q,0);
    const char *zValue = db_column_text(&q,1);
    manifest_reparent_checkin(rid, zValue);
  }
  db_finalize(&q);
  db_prepare(&q, "SELECT uuid FROM pending_tkt");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zUuid = db_column_text(&q, 0);





    ticket_rebuild_entry(zUuid);
    if( permitHooks && rc==TH_OK ){
      rc = xfer_run_script(zScript, zUuid, 0);



    }
  }
  db_finalize(&q);
  db_multi_exec("DROP TABLE pending_tkt");

  /* If multiple check-ins happen close together in time, adjust their
  ** times by a few milliseconds to make sure they appear in chronological
  ** order.
  */
  db_prepare(&q,
      "UPDATE time_fudge SET m1=m2-:incr WHERE m1>=m2 AND m1<m2+:window"







|

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



|







1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
  );
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q,0);
    const char *zValue = db_column_text(&q,1);
    manifest_reparent_checkin(rid, zValue);
  }
  db_finalize(&q);
  db_prepare(&q, "SELECT id FROM pending_xlink");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zId = db_column_text(&q, 0);
    char cType;
    if( zId==0 || zId[0]==0 ) continue;
    cType = zId[0];
    zId++;
    if( cType=='t' ){
      ticket_rebuild_entry(zId);
      if( permitHooks && rc==TH_OK ){
        rc = xfer_run_script(zScript, zId, 0);
      }
    }else if( cType=='w' ){
      backlink_wiki_refresh(zId);
    }
  }
  db_finalize(&q);
  db_multi_exec("DROP TABLE pending_xlink");

  /* If multiple check-ins happen close together in time, adjust their
  ** times by a few milliseconds to make sure they appear in chronological
  ** order.
  */
  db_prepare(&q,
      "UPDATE time_fudge SET m1=m2-:incr WHERE m1>=m2 AND m1<m2+:window"
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057

2058
2059
2060
2061
2062
2063
2064
    c = fossil_strcmp(pA->zName, pB->zName);
  }
  return c;
}

/*
** Scan artifact rid/pContent to see if it is a control artifact of
** any key:
**
**      *  Manifest
**      *  Control
**      *  Wiki Page
**      *  Ticket Change
**      *  Cluster
**      *  Attachment
**      *  Event

**
** If the input is a control artifact, then make appropriate entries
** in the auxiliary tables of the database in order to crosslink the
** artifact.
**
** If global variable g.xlinkClusterOnly is true, then ignore all
** control artifacts other than clusters.







|








>







2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
    c = fossil_strcmp(pA->zName, pB->zName);
  }
  return c;
}

/*
** Scan artifact rid/pContent to see if it is a control artifact of
** any type:
**
**      *  Manifest
**      *  Control
**      *  Wiki Page
**      *  Ticket Change
**      *  Cluster
**      *  Attachment
**      *  Event
**      *  Forum post
**
** If the input is a control artifact, then make appropriate entries
** in the auxiliary tables of the database in order to crosslink the
** artifact.
**
** If global variable g.xlinkClusterOnly is true, then ignore all
** control artifacts other than clusters.
2082
2083
2084
2085
2086
2087
2088

2089
2090

2091
2092
2093
2094
2095
2096
2097
    fossil_trace("-- manifest_crosslink(%d)\n", rid);
  }
  if( (p = manifest_cache_find(rid))!=0 ){
    blob_reset(pContent);
  }else if( (p = manifest_parse(pContent, rid, 0))==0 ){
    assert( blob_is_reset(pContent) || pContent==0 );
    if( (flags & MC_NO_ERRORS)==0 ){

      fossil_error(1, "syntax error in manifest [%S]",
                   db_text(0, "SELECT uuid FROM blob WHERE rid=%d",rid));

    }
    return 0;
  }
  if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
    manifest_destroy(p);
    assert( blob_is_reset(pContent) );
    if( (flags & MC_NO_ERRORS)==0 ) fossil_error(1, "no manifest");







>
|
<
>







2117
2118
2119
2120
2121
2122
2123
2124
2125

2126
2127
2128
2129
2130
2131
2132
2133
    fossil_trace("-- manifest_crosslink(%d)\n", rid);
  }
  if( (p = manifest_cache_find(rid))!=0 ){
    blob_reset(pContent);
  }else if( (p = manifest_parse(pContent, rid, 0))==0 ){
    assert( blob_is_reset(pContent) || pContent==0 );
    if( (flags & MC_NO_ERRORS)==0 ){
      char * zErrUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",rid);
      fossil_error(1, "syntax error in manifest [%S]", zErrUuid);

      fossil_free(zErrUuid);
    }
    return 0;
  }
  if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
    manifest_destroy(p);
    assert( blob_is_reset(pContent) );
    if( (flags & MC_NO_ERRORS)==0 ) fossil_error(1, "no manifest");
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
        rid, p->zUser, p->zComment,
        TAG_BGCOLOR, rid,
        TAG_USER, rid,
        TAG_COMMENT, rid, p->rDate
      );
      zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
                        " WHERE rowid=last_insert_rowid()");
      wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE);
      fossil_free(zCom);

      /* If this is a delta-manifest, record the fact that this repository
      ** contains delta manifests, to free the "commit" logic to generate
      ** new delta manifests.
      */
      if( p->zBaseline!=0 ){







|







2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
        rid, p->zUser, p->zComment,
        TAG_BGCOLOR, rid,
        TAG_USER, rid,
        TAG_COMMENT, rid, p->rDate
      );
      zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
                        " WHERE rowid=last_insert_rowid()");
      backlink_extract(zCom, 0, rid, BKLNK_COMMENT, p->rDate, 1);
      fossil_free(zCom);

      /* If this is a delta-manifest, record the fact that this repository
      ** contains delta manifests, to free the "commit" logic to generate
      ** new delta manifests.
      */
      if( p->zBaseline!=0 ){
2192
2193
2194
2195
2196
2197
2198

2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213

2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231


2232




2233


2234















2235





2236
2237
2238
2239
2240
2241
2242
      if( tid ){
        switch( p->aTag[i].zName[0] ){
          case '-':  type = 0;  break;  /* Cancel prior occurrences */
          case '+':  type = 1;  break;  /* Apply to target only */
          case '*':  type = 2;  break;  /* Propagate to descendants */
          default:
            fossil_error(1, "unknown tag type in manifest: %s", p->aTag);

            return 0;
        }
        tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue,
                   rid, p->rDate, tid);
      }
    }
    if( parentid ){
      tag_propagate_all(parentid);
    }
  }
  if( p->type==CFTYPE_WIKI ){
    char *zTag = mprintf("wiki-%s", p->zWikiTitle);
    int tagid = tag_findid(zTag, 1);
    int prior;
    char *zComment;

    int nWiki;
    char zLength[40];
    while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
    nWiki = strlen(p->zWiki);
    sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
    tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
    fossil_free(zTag);
    prior = db_int(0,
      "SELECT rid FROM tagxref"
      " WHERE tagid=%d AND mtime<%.17g"
      " ORDER BY mtime DESC",
      tagid, p->rDate
    );
    if( prior ){
      content_deltify(prior, &rid, 1, 0);
    }
    if( nWiki>0 ){
      zComment = mprintf("Changes to wiki page [%h]", p->zWikiTitle);


    }else{




      zComment = mprintf("Deleted wiki page [%h]", p->zWikiTitle);


    }















    search_doc_touch('w',rid,p->zWikiTitle);





    db_multi_exec(
      "REPLACE INTO event(type,mtime,objid,user,comment,"
      "                  bgcolor,euser,ecomment)"
      "VALUES('w',%.17g,%d,%Q,%Q,"
      "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
      "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
      "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",







>















>
















|
|
>
>

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

>
>
>
>
>







2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
      if( tid ){
        switch( p->aTag[i].zName[0] ){
          case '-':  type = 0;  break;  /* Cancel prior occurrences */
          case '+':  type = 1;  break;  /* Apply to target only */
          case '*':  type = 2;  break;  /* Propagate to descendants */
          default:
            fossil_error(1, "unknown tag type in manifest: %s", p->aTag);
            manifest_destroy(p);
            return 0;
        }
        tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue,
                   rid, p->rDate, tid);
      }
    }
    if( parentid ){
      tag_propagate_all(parentid);
    }
  }
  if( p->type==CFTYPE_WIKI ){
    char *zTag = mprintf("wiki-%s", p->zWikiTitle);
    int tagid = tag_findid(zTag, 1);
    int prior;
    char *zComment;
    const char *zPrefix;
    int nWiki;
    char zLength[40];
    while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
    nWiki = strlen(p->zWiki);
    sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
    tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
    fossil_free(zTag);
    prior = db_int(0,
      "SELECT rid FROM tagxref"
      " WHERE tagid=%d AND mtime<%.17g"
      " ORDER BY mtime DESC",
      tagid, p->rDate
    );
    if( prior ){
      content_deltify(prior, &rid, 1, 0);
    }
    if( nWiki<=0 ){
      zPrefix = "Deleted";
    }else if( !prior ){
      zPrefix = "Added";
    }else{
      zPrefix = "Changes to";
    }
    switch( wiki_page_type(p->zWikiTitle) ){
      case WIKITYPE_CHECKIN: {
        zComment = mprintf("%s wiki for check-in [%S]", zPrefix,
                           p->zWikiTitle+8);
        break;
      }
      case WIKITYPE_BRANCH: {
        zComment = mprintf("%s wiki for branch [/timeline?r=%t|%h]",
                           zPrefix, p->zWikiTitle+7, p->zWikiTitle+7);
        break;
      }
      case WIKITYPE_TAG: {
        zComment = mprintf("%s wiki for tag [/timeline?t=%t|%h]",
                           zPrefix, p->zWikiTitle+4, p->zWikiTitle+4);
        break;
      }
      default: {
        zComment = mprintf("%s wiki page [%h]", zPrefix, p->zWikiTitle);
        break;
      }
    }
    search_doc_touch('w',rid,p->zWikiTitle);
    if( manifest_crosslink_busy ){
      add_pending_crosslink('w',p->zWikiTitle);
    }else{
      backlink_wiki_refresh(p->zWikiTitle);
    }
    db_multi_exec(
      "REPLACE INTO event(type,mtime,objid,user,comment,"
      "                  bgcolor,euser,ecomment)"
      "VALUES('w',%.17g,%d,%Q,%Q,"
      "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
      "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
      "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
  if( p->type==CFTYPE_TICKET ){
    char *zTag;
    Stmt qatt;
    assert( manifest_crosslink_busy==1 );
    zTag = mprintf("tkt-%s", p->zTicketUuid);
    tag_insert(zTag, 1, 0, rid, p->rDate, rid);
    fossil_free(zTag);
    db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
                  p->zTicketUuid);
    /* Locate and update comment for any attachments */
    db_prepare(&qatt,
       "SELECT attachid, src, target, filename FROM attachment"
       " WHERE target=%Q",
       p->zTicketUuid
    );
    while( db_step(&qatt)==SQLITE_ROW ){







<
|







2395
2396
2397
2398
2399
2400
2401

2402
2403
2404
2405
2406
2407
2408
2409
  if( p->type==CFTYPE_TICKET ){
    char *zTag;
    Stmt qatt;
    assert( manifest_crosslink_busy==1 );
    zTag = mprintf("tkt-%s", p->zTicketUuid);
    tag_insert(zTag, 1, 0, rid, p->rDate, rid);
    fossil_free(zTag);

    add_pending_crosslink('t',p->zTicketUuid);
    /* Locate and update comment for any attachments */
    db_prepare(&qatt,
       "SELECT attachid, src, target, filename FROM attachment"
       " WHERE target=%Q",
       p->zTicketUuid
    );
    while( db_step(&qatt)==SQLITE_ROW ){
2539
2540
2541
2542
2543
2544
2545

2546
2547
2548
2549
2550
2551
2552
    blob_reset(&comment);
  }
  if( p->type==CFTYPE_FORUM ){
    int froot, fprev, firt;
    char *zFType;
    char *zTitle;
    schema_forum();

    froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid;
    fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
    firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
    db_multi_exec(
      "REPLACE INTO forumpost(fpid,froot,fprev,firt,fmtime)"
      "VALUES(%d,%d,nullif(%d,0),nullif(%d,0),%.17g)",
      p->rid, froot, fprev, firt, p->rDate







>







2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
    blob_reset(&comment);
  }
  if( p->type==CFTYPE_FORUM ){
    int froot, fprev, firt;
    char *zFType;
    char *zTitle;
    schema_forum();
    search_doc_touch('f', rid, 0);
    froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid;
    fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
    firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
    db_multi_exec(
      "REPLACE INTO forumpost(fpid,froot,fprev,firt,fmtime)"
      "VALUES(%d,%d,nullif(%d,0),nullif(%d,0),%.17g)",
      p->rid, froot, fprev, firt, p->rDate
Changes to src/markdown.md.
98
99
100
101
102
103
104
105
106






107
108
109
110
111
112
113
> For inline text, you can either use \``backticks`\` or the HTML
> `<code>` tag.
>
> For blocks of text or code:
>
> 1. Indent the text using a tab character or at least four spaces.
> 2. Precede the block with an HTML `<pre>` tag and follow it with `</pre>`.
> 3. Surround the block by \`\`\` (three or more) or \~\~\~ either at the
> left margin or indented no more than three spaces.







> With the standard skins, verbatim text is rendered in a fixed-width font,
> but that is purely a presentation matter, controlled by the skin’s CSS.

## Tables ##

>







|
|
>
>
>
>
>
>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
> For inline text, you can either use \``backticks`\` or the HTML
> `<code>` tag.
>
> For blocks of text or code:
>
> 1. Indent the text using a tab character or at least four spaces.
> 2. Precede the block with an HTML `<pre>` tag and follow it with `</pre>`.
> 3. Surround the block by <tt>\`\`\`</tt> (three or more) or <tt>\~\~\~</tt> either at the
> left margin or indented no more than three spaces. The first word
> on that same line (if any) is used in a “`language-WORD`” CSS style in
> the HTML rendering of that code block and is intended for use by
> code syntax highlighters. Thus <tt>\`\`\`c</tt> would mark a block of code
> in the C programming language. Text to be rendered inside the code block
> should therefore start on the next line, not be cuddled up with the
> backticks or tildes.

> With the standard skins, verbatim text is rendered in a fixed-width font,
> but that is purely a presentation matter, controlled by the skin’s CSS.

## Tables ##

>
Changes to src/merge.c.
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
**                           changes back to the nearest common ancestor.
**
**   -f|--force              Force the merge even if it would be a no-op.
**
**   --force-missing         Force the merge even if there is missing content.
**
**   --integrate             Merged branch will be closed when committing.




**
**   -n|--dry-run            If given, display instead of run actions
**
**   -v|--verbose            Show additional details of the merge
*/
void merge_cmd(void){
  int vid;              /* Current version "V" */
  int mid;              /* Version we are merging from "M" */
  int pid = 0;          /* The pivot version - most recent common ancestor P */
  int nid = 0;          /* The name pivot version "N" */
  int verboseFlag;      /* True if the -v|--verbose option is present */
  int integrateFlag;    /* True if the --integrate option is present */
  int pickFlag;         /* True if the --cherrypick option is present */
  int backoutFlag;      /* True if the --backout option is present */
  int dryRunFlag;       /* True if the --dry-run or -n option is present */
  int forceFlag;        /* True if the --force or -f option is present */
  int forceMissingFlag; /* True if the --force-missing option is present */
  const char *zBinGlob; /* The value of --binary */
  const char *zPivot;   /* The value of --baseline */
  int debugFlag;        /* True if --debug is present */

  int nConflict = 0;    /* Number of conflicts seen */
  int nOverwrite = 0;   /* Number of unmanaged files overwritten */
  char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */
  Stmt q;


  /* Notation:







>
>
>
>




















>







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
**                           changes back to the nearest common ancestor.
**
**   -f|--force              Force the merge even if it would be a no-op.
**
**   --force-missing         Force the merge even if there is missing content.
**
**   --integrate             Merged branch will be closed when committing.
**
**   -K|--keep-merge-files   On merge conflict, retain the temporary files
**                           used for merging, named *-baseline, *-original,
**                           and *-merge.
**
**   -n|--dry-run            If given, display instead of run actions
**
**   -v|--verbose            Show additional details of the merge
*/
void merge_cmd(void){
  int vid;              /* Current version "V" */
  int mid;              /* Version we are merging from "M" */
  int pid = 0;          /* The pivot version - most recent common ancestor P */
  int nid = 0;          /* The name pivot version "N" */
  int verboseFlag;      /* True if the -v|--verbose option is present */
  int integrateFlag;    /* True if the --integrate option is present */
  int pickFlag;         /* True if the --cherrypick option is present */
  int backoutFlag;      /* True if the --backout option is present */
  int dryRunFlag;       /* True if the --dry-run or -n option is present */
  int forceFlag;        /* True if the --force or -f option is present */
  int forceMissingFlag; /* True if the --force-missing option is present */
  const char *zBinGlob; /* The value of --binary */
  const char *zPivot;   /* The value of --baseline */
  int debugFlag;        /* True if --debug is present */
  int keepMergeFlag;    /* True if --keep-merge-files is present */
  int nConflict = 0;    /* Number of conflicts seen */
  int nOverwrite = 0;   /* Number of unmanaged files overwritten */
  char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */
  Stmt q;


  /* Notation:
273
274
275
276
277
278
279


280
281
282
283
284
285
286
  zBinGlob = find_option("binary",0,1);
  dryRunFlag = find_option("dry-run","n",0)!=0;
  if( !dryRunFlag ){
    dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */
  }
  forceFlag = find_option("force","f",0)!=0;
  zPivot = find_option("baseline",0,1);


  verify_all_options();
  db_must_be_within_tree();
  if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
  vid = db_lget_int("checkout", 0);
  if( vid==0 ){
    fossil_fatal("nothing is checked out");
  }







>
>







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  zBinGlob = find_option("binary",0,1);
  dryRunFlag = find_option("dry-run","n",0)!=0;
  if( !dryRunFlag ){
    dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */
  }
  forceFlag = find_option("force","f",0)!=0;
  zPivot = find_option("baseline",0,1);
  keepMergeFlag = find_option("keep-merge-files", "K",0)!=0;

  verify_all_options();
  db_must_be_within_tree();
  if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
  vid = db_lget_int("checkout", 0);
  if( vid==0 ){
    fossil_fatal("nothing is checked out");
  }
396
397
398
399
400
401
402







403
404
405
406
407
408
409
    fossil_print("Merge skipped because it is a no-op. "
                 " Use --force to override.\n");
    return;
  }
  if( integrateFlag && !is_a_leaf(mid)){
    fossil_warning("ignoring --integrate: %s is not a leaf", g.argv[2]);
    integrateFlag = 0;







  }
  if( verboseFlag ){
    print_checkin_description(mid, 12,
              integrateFlag ? "integrate:" : "merge-from:");
    print_checkin_description(pid, 12, "baseline:");
  }
  vfile_check_signature(vid, CKSIG_ENOTFILE);







>
>
>
>
>
>
>







403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
    fossil_print("Merge skipped because it is a no-op. "
                 " Use --force to override.\n");
    return;
  }
  if( integrateFlag && !is_a_leaf(mid)){
    fossil_warning("ignoring --integrate: %s is not a leaf", g.argv[2]);
    integrateFlag = 0;
  }
  if( integrateFlag && content_is_private(mid) ){
    fossil_warning(
      "ignoring --integrate: %s is on a private branch"
      "\n Use \"fossil amend --close\" (after commit) to close the leaf.",
      g.argv[2]);
    integrateFlag = 0;
  }
  if( verboseFlag ){
    print_checkin_description(mid, 12,
              integrateFlag ? "integrate:" : "merge-from:");
    print_checkin_description(pid, 12, "baseline:");
  }
  vfile_check_signature(vid, CKSIG_ENOTFILE);
663
664
665
666
667
668
669

670
671
672
673
674
675
676
      content_get(ridp, &p);
      content_get(ridm, &m);
      if( isBinary ){
        rc = -1;
        blob_zero(&r);
      }else{
        unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;

        rc = merge_3way(&p, zFullPath, &m, &r, mergeFlags);
      }
      if( rc>=0 ){
        if( !dryRunFlag ){
          blob_write_to_file(&r, zFullPath);
          file_setexe(zFullPath, isExe);
        }







>







677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
      content_get(ridp, &p);
      content_get(ridm, &m);
      if( isBinary ){
        rc = -1;
        blob_zero(&r);
      }else{
        unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
        if(keepMergeFlag!=0) mergeFlags |= MERGE_KEEP_FILES;
        rc = merge_3way(&p, zFullPath, &m, &r, mergeFlags);
      }
      if( rc>=0 ){
        if( !dryRunFlag ){
          blob_write_to_file(&r, zFullPath);
          file_setexe(zFullPath, isExe);
        }
Changes to src/merge3.c.
434
435
436
437
438
439
440






441
442
443
444
445
446
447
}

#if INTERFACE
/*
** Flags to the 3-way merger
*/
#define MERGE_DRYRUN  0x0001






#endif


/*
** This routine is a wrapper around blob_merge() with the following
** enhancements:
**







>
>
>
>
>
>







434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
}

#if INTERFACE
/*
** Flags to the 3-way merger
*/
#define MERGE_DRYRUN  0x0001
/*
** The MERGE_KEEP_FILES flag specifies that merge_3way() should retain
** its temporary files on error. By default they are removed after the
** merge, regardless of success or failure.
*/
#define MERGE_KEEP_FILES 0x0002
#endif


/*
** This routine is a wrapper around blob_merge() with the following
** enhancements:
**
463
464
465
466
467
468
469

470
471
472

473


474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510





511
512
513
514
515
516
517
518
  const char *zV1,    /* Name of file for version merging into (mine) */
  Blob *pV2,          /* Version merging from (yours) */
  Blob *pOut,         /* Output written here */
  unsigned mergeFlags /* Flags that control operation */
){
  Blob v1;            /* Content of zV1 */
  int rc;             /* Return code of subroutines and this routine */


  blob_read_from_file(&v1, zV1, ExtFILE);
  rc = blob_merge(pPivot, &v1, pV2, pOut);

  if( rc!=0 && (mergeFlags & MERGE_DRYRUN)==0 ){


    char *zPivot;       /* Name of the pivot file */
    char *zOrig;        /* Name of the original content file */
    char *zOther;       /* Name of the merge file */

    zPivot = file_newname(zV1, "baseline", 1);
    blob_write_to_file(pPivot, zPivot);
    zOrig = file_newname(zV1, "original", 1);
    blob_write_to_file(&v1, zOrig);
    zOther = file_newname(zV1, "merge", 1);
    blob_write_to_file(pV2, zOther);
    if( rc>0 ){
      const char *zGMerge;   /* Name of the gmerge command */

      zGMerge = db_get("gmerge-command", 0);
      if( zGMerge && zGMerge[0] ){
        char *zOut;     /* Temporary output file */
        char *zCmd;     /* Command to invoke */
        const char *azSubst[8];  /* Strings to be substituted */

        zOut = file_newname(zV1, "output", 1);
        azSubst[0] = "%baseline";  azSubst[1] = zPivot;
        azSubst[2] = "%original";  azSubst[3] = zOrig;
        azSubst[4] = "%merge";     azSubst[5] = zOther;
        azSubst[6] = "%output";    azSubst[7] = zOut;
        zCmd = string_subst(zGMerge, 8, azSubst);
        printf("%s\n", zCmd); fflush(stdout);
        fossil_system(zCmd);
        if( file_size(zOut, RepoFILE)>=0 ){
          blob_read_from_file(pOut, zOut, ExtFILE);
          file_delete(zPivot);
          file_delete(zOrig);
          file_delete(zOther);
          file_delete(zOut);
        }
        fossil_free(zCmd);
        fossil_free(zOut);
      }





    }
    fossil_free(zPivot);
    fossil_free(zOrig);
    fossil_free(zOther);
  }
  blob_reset(&v1);
  return rc;
}







>



>
|
>
>











<
<
<




<










<
<
<





>
>
>
>
>








469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494



495
496
497
498

499
500
501
502
503
504
505
506
507
508



509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
  const char *zV1,    /* Name of file for version merging into (mine) */
  Blob *pV2,          /* Version merging from (yours) */
  Blob *pOut,         /* Output written here */
  unsigned mergeFlags /* Flags that control operation */
){
  Blob v1;            /* Content of zV1 */
  int rc;             /* Return code of subroutines and this routine */
  const char *zGMerge;   /* Name of the gmerge command */

  blob_read_from_file(&v1, zV1, ExtFILE);
  rc = blob_merge(pPivot, &v1, pV2, pOut);
  zGMerge = rc<=0 ? 0 : db_get("gmerge-command", 0);
  if( (mergeFlags & MERGE_DRYRUN)==0
      && ((zGMerge!=0 && zGMerge[0]!=0)
          || (rc!=0 && (mergeFlags & MERGE_KEEP_FILES)!=0)) ){
    char *zPivot;       /* Name of the pivot file */
    char *zOrig;        /* Name of the original content file */
    char *zOther;       /* Name of the merge file */

    zPivot = file_newname(zV1, "baseline", 1);
    blob_write_to_file(pPivot, zPivot);
    zOrig = file_newname(zV1, "original", 1);
    blob_write_to_file(&v1, zOrig);
    zOther = file_newname(zV1, "merge", 1);
    blob_write_to_file(pV2, zOther);
    if( rc>0 ){



      if( zGMerge && zGMerge[0] ){
        char *zOut;     /* Temporary output file */
        char *zCmd;     /* Command to invoke */
        const char *azSubst[8];  /* Strings to be substituted */

        zOut = file_newname(zV1, "output", 1);
        azSubst[0] = "%baseline";  azSubst[1] = zPivot;
        azSubst[2] = "%original";  azSubst[3] = zOrig;
        azSubst[4] = "%merge";     azSubst[5] = zOther;
        azSubst[6] = "%output";    azSubst[7] = zOut;
        zCmd = string_subst(zGMerge, 8, azSubst);
        printf("%s\n", zCmd); fflush(stdout);
        fossil_system(zCmd);
        if( file_size(zOut, RepoFILE)>=0 ){
          blob_read_from_file(pOut, zOut, ExtFILE);



          file_delete(zOut);
        }
        fossil_free(zCmd);
        fossil_free(zOut);
      }
    }
    if( (mergeFlags & MERGE_KEEP_FILES)==0 ){
      file_delete(zPivot);
      file_delete(zOrig);
      file_delete(zOther);
    }
    fossil_free(zPivot);
    fossil_free(zOrig);
    fossil_free(zOther);
  }
  blob_reset(&v1);
  return rc;
}
Changes to src/mkindex.c.
511
512
513
514
515
516
517

518
519
520
521
522
523
524
  }
  fclose(in);
  nUsed = nFixed;
}

int main(int argc, char **argv){
  int i;

  for(i=1; i<argc; i++){
    zFile = argv[i];
    process_file();
  }
  build_table();
  return nErr;
}







>







511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
  }
  fclose(in);
  nUsed = nFixed;
}

int main(int argc, char **argv){
  int i;
  memset(aEntry, 0, sizeof(Entry) * N_ENTRY);
  for(i=1; i<argc; i++){
    zFile = argv[i];
    process_file();
  }
  build_table();
  return nErr;
}
Changes to src/mkversion.c.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
/*
** This C program generates the "VERSION.h" header file from information
** extracted out of the "manifest", "manifest.uuid", and "VERSION" files.
** Call this program with three arguments:
**
**     ./a.out manifest.uuid manifest VERSION
**
** Note that the manifest.uuid and manifest files are generated by Fossil.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


static FILE *open_for_reading(const char *zFilename){
  FILE *f = fopen(zFilename, "r");
  if( f==0 ){
    fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
    exit(1);
  }












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
** This C program generates the "VERSION.h" header file from information
** extracted out of the "manifest", "manifest.uuid", and "VERSION" files.
** Call this program with three arguments:
**
**     ./a.out manifest.uuid manifest VERSION
**
** Note that the manifest.uuid and manifest files are generated by Fossil.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

static FILE *open_for_reading(const char *zFilename){
  FILE *f = fopen(zFilename, "r");
  if( f==0 ){
    fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
    exit(1);
  }
44
45
46
47
48
49
50
51


52
53



54










55
56
57
58
59
60
61
    fclose(u);
    for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
    *z = 0;
    printf("#define MANIFEST_UUID \"%s\"\n",b);
    printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b);
    m = open_for_reading(argv[2]);
    while(b ==  fgets(b, sizeof(b)-1,m)){
        if(0 == strncmp("D ",b,2)){


            printf("#define MANIFEST_DATE \"%.10s %.8s\"\n",b+2,b+13);
            printf("#define MANIFEST_YEAR \"%.4s\"\n",b+2);



        }










    }
    fclose(m);
    v = open_for_reading(argv[3]);
    if( fgets(b, sizeof(b)-1,v)==0 ){
      fprintf(stderr, "malformed VERSION file: %s\n", argv[3]);
      exit(1);
    }







|
>
>
|
|
>
>
>

>
>
>
>
>
>
>
>
>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    fclose(u);
    for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
    *z = 0;
    printf("#define MANIFEST_UUID \"%s\"\n",b);
    printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b);
    m = open_for_reading(argv[2]);
    while(b ==  fgets(b, sizeof(b)-1,m)){
      if(0 == strncmp("D ",b,2)){
        int k, n;
        char zDateNum[30];
        printf("#define MANIFEST_DATE \"%.10s %.8s\"\n",b+2,b+13);
        printf("#define MANIFEST_YEAR \"%.4s\"\n",b+2);
        n = 0;
        for(k=0; k<10; k++){
          if( isdigit(b[k+2]) ) zDateNum[n++] = b[k+2];
        }
        zDateNum[n] = 0;
        printf("#define MANIFEST_NUMERIC_DATE %s\n", zDateNum);
        n = 0;
        for(k=0; k<8; k++){
          if( isdigit(b[k+13]) ) zDateNum[n++] = b[k+13];
        }
        zDateNum[n] = 0;
        for(k=0; zDateNum[k]=='0'; k++){}
        printf("#define MANIFEST_NUMERIC_TIME %s\n", zDateNum+k);
      }
    }
    fclose(m);
    v = open_for_reading(argv[3]);
    if( fgets(b, sizeof(b)-1,v)==0 ){
      fprintf(stderr, "malformed VERSION file: %s\n", argv[3]);
      exit(1);
    }
Changes to src/moderate.c.
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
  }
  db_end_transaction(0);
}

/*
** Approve an object held for moderation.
*/
void moderation_approve(int rid){
  if( !moderation_pending(rid) ) return;
  db_begin_transaction();
  db_multi_exec(
    "DELETE FROM private WHERE rid=%d;"
    "INSERT OR IGNORE INTO unclustered VALUES(%d);"
    "INSERT OR IGNORE INTO unsent VALUES(%d);",
    rid, rid, rid
  );
  db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
  admin_log("Approved moderation of rid %d.", rid);

  db_end_transaction(0);
}

/*
** WEBPAGE: modreq
**
** Show all pending moderation request







|









|
>







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
  }
  db_end_transaction(0);
}

/*
** Approve an object held for moderation.
*/
void moderation_approve(char class, int rid){
  if( !moderation_pending(rid) ) return;
  db_begin_transaction();
  db_multi_exec(
    "DELETE FROM private WHERE rid=%d;"
    "INSERT OR IGNORE INTO unclustered VALUES(%d);"
    "INSERT OR IGNORE INTO unsent VALUES(%d);",
    rid, rid, rid
  );
  db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
  admin_log("Approved moderation of rid %c-%d.", class, rid);
  if( class!='a' ) search_doc_touch(class, rid, 0);
  db_end_transaction(0);
}

/*
** WEBPAGE: modreq
**
** Show all pending moderation request
Changes to src/name.c.
103
104
105
106
107
108
109

































110
111
112
113
114
115
116
  if( bVerifyNotAHash ){
    if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%q*'",zIn) ) return 0;
  }

  /* It looks like this may be a date.  Return it with punctuation added. */
  return zEDate;
}


































/*
** Return the RID that is the "root" of the branch that contains
** check-in "rid".  Details depending on eType:
**
**    eType==0    The check-in of the parent branch off of which
**                the branch containing RID originally diverged.







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







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  if( bVerifyNotAHash ){
    if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%q*'",zIn) ) return 0;
  }

  /* It looks like this may be a date.  Return it with punctuation added. */
  return zEDate;
}

/*
** The data-time string in the argument is going to be used as an
** upper bound like this:    mtime<=julianday(zDate,'localtime').
** But if the zDate parameter omits the fractional seconds or the
** seconds, or the time, that might mess up the == part of the
** comparison.  So add in missing factional seconds or seconds or time.
**
** The returned string is held in a static buffer that is overwritten
** with each call, or else is just a copy of its input if there are
** no changes.
*/
const char *fossil_roundup_date(const char *zDate){
  static char zUp[24];
  int n = (int)strlen(zDate);
  if( n==19 ){  /* YYYY-MM-DD HH:MM:SS */
    memcpy(zUp, zDate, 19);
    memcpy(zUp+19, ".999", 5);
    return zUp;
  }
  if( n==16 ){ /* YYYY-MM-DD HH:MM */
    memcpy(zUp, zDate, 16);
    memcpy(zUp+16, ":59.999", 8);
    return zUp;
  }
  if( n==10 ){ /* YYYY-MM-DD */
    memcpy(zUp, zDate, 10);
    memcpy(zUp+10, " 23:59:59.999", 14);
    return zUp;
  }
  return zDate;
}


/*
** Return the RID that is the "root" of the branch that contains
** check-in "rid".  Details depending on eType:
**
**    eType==0    The check-in of the parent branch off of which
**                the branch containing RID originally diverged.
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
  if( memcmp(zTag, "date:", 5)==0 ){
    zDate = fossil_expand_datetime(&zTag[5],0);
    if( zDate==0 ) zDate = &zTag[5];
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      zDate, zType);
    return rid;
  }
  if( fossil_isdate(zTag) ){
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      zTag, zType);
    if( rid) return rid;
  }

  /* Deprecated date & time formats:   "local:" + date-time and
  ** "utc:" + date-time */
  if( memcmp(zTag, "local:", 6)==0 ){
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      &zTag[6], zType);
    return rid;
  }
  if( memcmp(zTag, "utc:", 4)==0 ){
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      &zTag[4], zType);
    return rid;
  }

  /* "tag:" + symbolic-name */
  if( memcmp(zTag, "tag:", 4)==0 ){
    rid = db_int(0,
       "SELECT event.objid, max(event.mtime)"







|







|


















|







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  if( memcmp(zTag, "date:", 5)==0 ){
    zDate = fossil_expand_datetime(&zTag[5],0);
    if( zDate==0 ) zDate = &zTag[5];
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      fossil_roundup_date(zDate), zType);
    return rid;
  }
  if( fossil_isdate(zTag) ){
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      fossil_roundup_date(zTag), zType);
    if( rid) return rid;
  }

  /* Deprecated date & time formats:   "local:" + date-time and
  ** "utc:" + date-time */
  if( memcmp(zTag, "local:", 6)==0 ){
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      &zTag[6], zType);
    return rid;
  }
  if( memcmp(zTag, "utc:", 4)==0 ){
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      fossil_roundup_date(&zTag[4]), zType);
    return rid;
  }

  /* "tag:" + symbolic-name */
  if( memcmp(zTag, "tag:", 4)==0 ){
    rid = db_int(0,
       "SELECT event.objid, max(event.mtime)"
292
293
294
295
296
297
298
299
300


301
302

303
304
305
306
307


308
309
310
311
312
313
314
315
316
317


318
319
320
321
322
323
324
  if( strncmp(zTag, "merge-in:", 9)==0 ){
    rid = symbolic_name_to_rid(zTag+9, zType);
    return start_of_branch(rid, 2);
  }

  /* symbolic-name ":" date-time */
  nTag = strlen(zTag);
  for(i=0; i<nTag-10 && zTag[i]!=':'; i++){}
  if( zTag[i]==':' && fossil_isdate(&zTag[i+1]) ){


    char *zDate = mprintf("%s", &zTag[i+1]);
    char *zTagBase = mprintf("%.*s", i, zTag);

    int nDate = strlen(zDate);
    if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
      zDate[nDate-3] = 'z';
      zDate[nDate-2] = 0;
    }


    rid = db_int(0,
      "SELECT event.objid, max(event.mtime)"
      "  FROM tag, tagxref, event"
      " WHERE tag.tagname='sym-%q' "
      "   AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
      "   AND event.objid=tagxref.rid "
      "   AND event.mtime<=julianday(%Q)"
      "   AND event.type GLOB '%q'",
      zTagBase, zDate, zType
    );


    return rid;
  }

  /* Remove optional [...] */
  zXTag = zTag;
  nXTag = nTag;
  if( zXTag[0]=='[' ){







|
|
>
>


>





>
>






|

|

>
>







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
  if( strncmp(zTag, "merge-in:", 9)==0 ){
    rid = symbolic_name_to_rid(zTag+9, zType);
    return start_of_branch(rid, 2);
  }

  /* symbolic-name ":" date-time */
  nTag = strlen(zTag);
  for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
  if( zTag[i]==':' 
   && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0)!=0)
  ){
    char *zDate = mprintf("%s", &zTag[i+1]);
    char *zTagBase = mprintf("%.*s", i, zTag);
    char *zXDate;
    int nDate = strlen(zDate);
    if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
      zDate[nDate-3] = 'z';
      zDate[nDate-2] = 0;
    }
    zXDate = fossil_expand_datetime(zDate,0);
    if( zXDate==0 ) zXDate = zDate;
    rid = db_int(0,
      "SELECT event.objid, max(event.mtime)"
      "  FROM tag, tagxref, event"
      " WHERE tag.tagname='sym-%q' "
      "   AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
      "   AND event.objid=tagxref.rid "
      "   AND event.mtime<=julianday(%Q,fromLocal())"
      "   AND event.type GLOB '%q'",
      zTagBase, fossil_roundup_date(zXDate), zType
    );
    fossil_free(zDate);
    fossil_free(zTagBase);
    return rid;
  }

  /* Remove optional [...] */
  zXTag = zTag;
  nXTag = nTag;
  if( zXTag[0]=='[' ){
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  /* Pure numeric date/time */
  zDate = fossil_expand_datetime(zTag, 0);
  if( zDate ){
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      zDate, zType);
    if( rid) return rid;
  }


  /* Undocumented:  numeric tags get translated directly into the RID */
  if( memcmp(zTag, "rid:", 4)==0 ){
    zTag += 4;







|







419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  /* Pure numeric date/time */
  zDate = fossil_expand_datetime(zTag, 0);
  if( zDate ){
    rid = db_int(0,
      "SELECT objid FROM event"
      " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
      " ORDER BY mtime DESC LIMIT 1",
      fossil_roundup_date(zDate), zType);
    if( rid) return rid;
  }


  /* Undocumented:  numeric tags get translated directly into the RID */
  if( memcmp(zTag, "rid:", 4)==0 ){
    zTag += 4;
920
921
922
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
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028

1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050

1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064

1065
1066
1067


1068
1069
1070
1071
1072
1073
1074




1075
1076
1077
1078
1079
1080
1081
static const char zDescTab[] =
@ CREATE TEMP TABLE IF NOT EXISTS description(
@   rid INTEGER PRIMARY KEY,       -- RID of the object
@   uuid TEXT,                     -- hash of the object
@   ctime DATETIME,                -- Time of creation
@   isPrivate BOOLEAN DEFAULT 0,   -- True for unpublished artifacts
@   type TEXT,                     -- file, checkin, wiki, ticket, etc.

@   summary TEXT,                  -- Summary comment for the object
@   detail TEXT                    -- File name, check-in comment, etc
@ );

;


































































/*
** Create the description table if it does not already exists.
** Populate fields of this table with descriptions for all artifacts
** whose RID matches the SQL expression in zWhere.
*/
void describe_artifacts(const char *zWhere){
  db_multi_exec("%s", zDescTab/*safe-for-%s*/);

  /* Describe check-ins */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, event.mtime, 'checkin',\n"
    "       'check-in on ' || strftime('%%Y-%%m-%%d %%H:%%M',event.mtime)\n"
    "  FROM event, blob\n"
    " WHERE (event.objid %s) AND event.type='ci'\n"
    "   AND event.objid=blob.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Describe files */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, event.mtime, 'file', 'file '||filename.name\n"

    "  FROM mlink, blob, event, filename\n"
    " WHERE (mlink.fid %s)\n"
    "   AND mlink.mid=event.objid\n"
    "   AND filename.fnid=mlink.fnid\n"
    "   AND mlink.fid=blob.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Describe tags */
  db_multi_exec(
   "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, tagxref.mtime, 'tag',\n"
    "     'tag '||substr((SELECT uuid FROM blob WHERE rid=tagxref.rid),1,16)\n"
    "  FROM tagxref, blob\n"
    " WHERE (tagxref.srcid %s) AND tagxref.srcid!=tagxref.rid\n"
    "   AND tagxref.srcid=blob.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Cluster artifacts */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, rcvfrom.mtime, 'cluster', 'cluster'\n"

    "  FROM tagxref, blob, rcvfrom\n"
    " WHERE (tagxref.rid %s)\n"
    "   AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='cluster')\n"
    "   AND blob.rid=tagxref.rid"
    "   AND rcvfrom.rcvid=blob.rcvid;",
    zWhere /*safe-for-%s*/
  );

  /* Ticket change artifacts */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, tagxref.mtime, 'ticket',\n"
    "       'ticket '||substr(tag.tagname,5,21)\n"
    "  FROM tagxref, tag, blob\n"
    " WHERE (tagxref.rid %s)\n"
    "   AND tag.tagid=tagxref.tagid\n"
    "   AND tag.tagname GLOB 'tkt-*'"
    "   AND blob.rid=tagxref.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Wiki edit artifacts */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, tagxref.mtime, 'wiki',\n"
    "       printf('wiki \"%%s\"',substr(tag.tagname,6))\n"
    "  FROM tagxref, tag, blob\n"
    " WHERE (tagxref.rid %s)\n"
    "   AND tag.tagid=tagxref.tagid\n"
    "   AND tag.tagname GLOB 'wiki-*'"
    "   AND blob.rid=tagxref.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Event edit artifacts */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, tagxref.mtime, 'event',\n"
    "       'event '||substr(tag.tagname,7)\n"
    "  FROM tagxref, tag, blob\n"
    " WHERE (tagxref.rid %s)\n"
    "   AND tag.tagid=tagxref.tagid\n"
    "   AND tag.tagname GLOB 'event-*'"
    "   AND blob.rid=tagxref.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Attachments */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, attachment.mtime, 'attach-control',\n"

    "       'attachment-control for '||attachment.filename\n"
    "  FROM attachment, blob\n"
    " WHERE (attachment.attachid %s)\n"
    "   AND blob.rid=attachment.attachid",
    zWhere /*safe-for-%s*/
  );
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, attachment.mtime, 'attachment',\n"
    "       'attachment '||attachment.filename\n"
    "  FROM attachment, blob\n"
    " WHERE (blob.rid %s)\n"
    "   AND blob.rid NOT IN (SELECT rid FROM description)\n"
    "   AND blob.uuid=attachment.src",
    zWhere /*safe-for-%s*/
  );

  /* Forum posts */
  if( db_table_exists("repository","forumpost") ){
    db_multi_exec(
      "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n"
      "SELECT postblob.rid, postblob.uuid, forumpost.fmtime, 'forumpost',\n"

      "       CASE WHEN fpid=froot THEN 'forum-post '\n"
      "            ELSE 'forum-reply-to ' END || substr(rootblob.uuid,1,14)\n"
      "  FROM forumpost, blob AS postblob, blob AS rootblob\n"
      " WHERE (forumpost.fpid %s)\n"
      "   AND postblob.rid=forumpost.fpid"
      "   AND rootblob.rid=forumpost.froot",
      zWhere /*safe-for-%s*/
    );
  }

  /* Everything else */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,type,summary)\n"
    "SELECT blob.rid, blob.uuid,"

    "       CASE WHEN blob.size<0 THEN 'phantom' ELSE '' END,\n"
    "       'unknown'\n"
    "  FROM blob WHERE (blob.rid %s);",


    zWhere /*safe-for-%s*/
  );

  /* Mark private elements */
  db_multi_exec(
   "UPDATE description SET isPrivate=1 WHERE rid IN private"
  );




}

/*
** Print the content of the description table on stdout.
**
** The description table is computed using the WHERE clause zWhere if
** the zWhere parameter is not NULL.  If zWhere is NULL, then this







>

|

>

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











|
|









|
|
>










|
|









|
|
>










|
|











|
|











|
|











|
|
>







|
|











|
|
>










|

|
|
>
|

|
>
>







>
>
>
>







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
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
static const char zDescTab[] =
@ CREATE TEMP TABLE IF NOT EXISTS description(
@   rid INTEGER PRIMARY KEY,       -- RID of the object
@   uuid TEXT,                     -- hash of the object
@   ctime DATETIME,                -- Time of creation
@   isPrivate BOOLEAN DEFAULT 0,   -- True for unpublished artifacts
@   type TEXT,                     -- file, checkin, wiki, ticket, etc.
@   rcvid INT,                     -- When the artifact was received
@   summary TEXT,                  -- Summary comment for the object
@   ref TEXT                       -- hash of an object to link against
@ );
@ CREATE INDEX desctype ON description(summary) WHERE summary='unknown';
;

/*
** Attempt to describe all phantom artifacts.  The artifacts are
** already loaded into the description table and have summary='unknown'.
** This routine attempts to generate a better summary, and possibly
** fill in the ref field.
*/
static void describe_unknown_artifacts(){
  /* Try to figure out the origin of unknown artifacts */
  db_multi_exec(
    "REPLACE INTO description(rid,uuid,isPrivate,type,summary,ref)\n"
    "  SELECT description.rid, description.uuid, isPrivate, type,\n"
    "         CASE WHEN plink.isprim THEN '' ELSE 'merge ' END ||\n"
    "         'parent of check-in', blob.uuid\n"
    "    FROM description, plink, blob\n"
    "   WHERE description.summary='unknown'\n"
    "     AND plink.pid=description.rid\n"
    "     AND blob.rid=plink.cid;"
  );
  db_multi_exec(
    "REPLACE INTO description(rid,uuid,isPrivate,type,summary,ref)\n"
    "  SELECT description.rid, description.uuid, isPrivate, type,\n"
    "         'child of check-in', blob.uuid\n"
    "    FROM description, plink, blob\n"
    "   WHERE description.summary='unknown'\n"
    "     AND plink.cid=description.rid\n"
    "     AND blob.rid=plink.pid;"
  );
  db_multi_exec(
    "REPLACE INTO description(rid,uuid,isPrivate,type,summary,ref)\n"
    "  SELECT description.rid, description.uuid, isPrivate, type,\n"
    "         'check-in referenced by \"'||tag.tagname ||'\" tag',\n"
    "         blob.uuid\n"
    "    FROM description, tagxref, tag, blob\n"
    "   WHERE description.summary='unknown'\n"
    "     AND tagxref.origid=description.rid\n"
    "     AND tag.tagid=tagxref.tagid\n"
    "     AND blob.rid=tagxref.srcid;"
  );
  db_multi_exec(
    "REPLACE INTO description(rid,uuid,isPrivate,type,summary,ref)\n"
    "  SELECT description.rid, description.uuid, isPrivate, type,\n"
    "         'file \"'||filename.name||'\"',\n"
    "         blob.uuid\n"
    "    FROM description, mlink, filename, blob\n"
    "   WHERE description.summary='unknown'\n"
    "     AND mlink.fid=description.rid\n"
    "     AND blob.rid=mlink.mid\n"
    "     AND filename.fnid=mlink.fnid;"
  );
  if( !db_exists("SELECT 1 FROM description WHERE summary='unknown'") ){
    return;
  }
  add_content_sql_commands(g.db);
  db_multi_exec(
    "REPLACE INTO description(rid,uuid,isPrivate,type,summary,ref)\n"
    "  SELECT description.rid, description.uuid, isPrivate, type,\n"
    "         'referenced by cluster', blob.uuid\n"
    "    FROM description, tagxref, blob\n"
    "   WHERE description.summary='unknown'\n"
    "     AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='cluster')\n"
    "     AND blob.rid=tagxref.rid\n"
    "     AND content(blob.uuid) GLOB ('*M '||blob.uuid||'*');"
  );
}

/*
** Create the description table if it does not already exists.
** Populate fields of this table with descriptions for all artifacts
** whose RID matches the SQL expression in zWhere.
*/
void describe_artifacts(const char *zWhere){
  db_multi_exec("%s", zDescTab/*safe-for-%s*/);

  /* Describe check-ins */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, event.mtime, 'checkin',\n"
    "       'check-in on ' || strftime('%%Y-%%m-%%d %%H:%%M',event.mtime)\n"
    "  FROM event, blob\n"
    " WHERE (event.objid %s) AND event.type='ci'\n"
    "   AND event.objid=blob.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Describe files */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, event.mtime,"
    "       'file', 'file '||filename.name\n"
    "  FROM mlink, blob, event, filename\n"
    " WHERE (mlink.fid %s)\n"
    "   AND mlink.mid=event.objid\n"
    "   AND filename.fnid=mlink.fnid\n"
    "   AND mlink.fid=blob.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Describe tags */
  db_multi_exec(
   "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, tagxref.mtime, 'tag',\n"
    "     'tag '||substr((SELECT uuid FROM blob WHERE rid=tagxref.rid),1,16)\n"
    "  FROM tagxref, blob\n"
    " WHERE (tagxref.srcid %s) AND tagxref.srcid!=tagxref.rid\n"
    "   AND tagxref.srcid=blob.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Cluster artifacts */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, rcvfrom.mtime,"
    "       'cluster', 'cluster'\n"
    "  FROM tagxref, blob, rcvfrom\n"
    " WHERE (tagxref.rid %s)\n"
    "   AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='cluster')\n"
    "   AND blob.rid=tagxref.rid"
    "   AND rcvfrom.rcvid=blob.rcvid;",
    zWhere /*safe-for-%s*/
  );

  /* Ticket change artifacts */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, tagxref.mtime, 'ticket',\n"
    "       'ticket '||substr(tag.tagname,5,21)\n"
    "  FROM tagxref, tag, blob\n"
    " WHERE (tagxref.rid %s)\n"
    "   AND tag.tagid=tagxref.tagid\n"
    "   AND tag.tagname GLOB 'tkt-*'"
    "   AND blob.rid=tagxref.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Wiki edit artifacts */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, tagxref.mtime, 'wiki',\n"
    "       printf('wiki \"%%s\"',substr(tag.tagname,6))\n"
    "  FROM tagxref, tag, blob\n"
    " WHERE (tagxref.rid %s)\n"
    "   AND tag.tagid=tagxref.tagid\n"
    "   AND tag.tagname GLOB 'wiki-*'"
    "   AND blob.rid=tagxref.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Event edit artifacts */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, tagxref.mtime, 'event',\n"
    "       'event '||substr(tag.tagname,7)\n"
    "  FROM tagxref, tag, blob\n"
    " WHERE (tagxref.rid %s)\n"
    "   AND tag.tagid=tagxref.tagid\n"
    "   AND tag.tagname GLOB 'event-*'"
    "   AND blob.rid=tagxref.rid;",
    zWhere /*safe-for-%s*/
  );

  /* Attachments */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, attachment.mtime,"
    "       'attach-control',\n"
    "       'attachment-control for '||attachment.filename\n"
    "  FROM attachment, blob\n"
    " WHERE (attachment.attachid %s)\n"
    "   AND blob.rid=attachment.attachid",
    zWhere /*safe-for-%s*/
  );
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
    "SELECT blob.rid, blob.uuid, blob.rcvid, attachment.mtime, 'attachment',\n"
    "       'attachment '||attachment.filename\n"
    "  FROM attachment, blob\n"
    " WHERE (blob.rid %s)\n"
    "   AND blob.rid NOT IN (SELECT rid FROM description)\n"
    "   AND blob.uuid=attachment.src",
    zWhere /*safe-for-%s*/
  );

  /* Forum posts */
  if( db_table_exists("repository","forumpost") ){
    db_multi_exec(
      "INSERT OR IGNORE INTO description(rid,uuid,rcvid,ctime,type,summary)\n"
      "SELECT postblob.rid, postblob.uuid, postblob.rcvid,"
      "       forumpost.fmtime, 'forumpost',\n"
      "       CASE WHEN fpid=froot THEN 'forum-post '\n"
      "            ELSE 'forum-reply-to ' END || substr(rootblob.uuid,1,14)\n"
      "  FROM forumpost, blob AS postblob, blob AS rootblob\n"
      " WHERE (forumpost.fpid %s)\n"
      "   AND postblob.rid=forumpost.fpid"
      "   AND rootblob.rid=forumpost.froot",
      zWhere /*safe-for-%s*/
    );
  }

  /* Mark all other artifacts as "unknown" for now */
  db_multi_exec(
    "INSERT OR IGNORE INTO description(rid,uuid,rcvid,type,summary)\n"
    "SELECT blob.rid, blob.uuid,blob.rcvid,\n"
    "       CASE WHEN EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)\n"
           " THEN 'phantom' ELSE '' END,\n"
    "       'unknown'\n"
    "  FROM blob\n"
    " WHERE (blob.rid %s)\n"
    "   AND (blob.rid NOT IN (SELECT rid FROM description));",
    zWhere /*safe-for-%s*/
  );

  /* Mark private elements */
  db_multi_exec(
   "UPDATE description SET isPrivate=1 WHERE rid IN private"
  );

  if( db_exists("SELECT 1 FROM description WHERE summary='unknown'") ){
    describe_unknown_artifacts();
  }
}

/*
** Print the content of the description table on stdout.
**
** The description table is computed using the WHERE clause zWhere if
** the zWhere parameter is not NULL.  If zWhere is NULL, then this
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
  );
  while( db_step(&q)==SQLITE_ROW ){
    if( zLabel ){
      fossil_print("%s\n", zLabel);
      zLabel = 0;
    }
    fossil_print("  %.16s %s", db_column_text(&q,0), db_column_text(&q,1));
    if( db_column_int(&q,2) ) fossil_print(" (unpublished)");
    fossil_print("\n");
    cnt++;
  }
  db_finalize(&q);
  if( zWhere!=0 ) db_multi_exec("DELETE FROM description;");
  return cnt;
}







|







1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
  );
  while( db_step(&q)==SQLITE_ROW ){
    if( zLabel ){
      fossil_print("%s\n", zLabel);
      zLabel = 0;
    }
    fossil_print("  %.16s %s", db_column_text(&q,0), db_column_text(&q,1));
    if( db_column_int(&q,2) ) fossil_print(" (private)");
    fossil_print("\n");
    cnt++;
  }
  db_finalize(&q);
  if( zWhere!=0 ) db_multi_exec("DELETE FROM description;");
  return cnt;
}
1130
1131
1132
1133
1134
1135
1136
1137

1138
1139
1140
1141
1142
1143
1144
1145

1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156










1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177


1178
1179
1180
1181
1182
1183
1184

1185
1186
1187
1188
1189
1190
1191
1192
1193





1194
1195
1196
1197
1198






1199
1200
1201
1202
1203
1204
1205








1206






1207







1208
1209
1210
1211
1212
1213






































































1214
1215
1216
1217
1218
1219
1220
/*
** WEBPAGE: bloblist
**
** Return a page showing all artifacts in the repository.  Query parameters:
**
**   n=N         Show N artifacts
**   s=S         Start with artifact number S
**   unpub       Show only unpublished artifacts

**   hclr        Color code hash types (SHA1 vs SHA3)
*/
void bloblist_page(void){
  Stmt q;
  int s = atoi(PD("s","0"));
  int n = atoi(PD("n","5000"));
  int mx = db_int(0, "SELECT max(rid) FROM blob");
  int unpubOnly = PB("unpub");

  int hashClr = PB("hclr");
  char *zRange;
  char *zSha1Bg;
  char *zSha3Bg;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_header("List Of Artifacts");
  style_submenu_element("250 Largest", "bigbloblist");
  if( g.perm.Admin ){
    style_submenu_element("Artifact Log", "rcvfromlist");










  }
  if( g.perm.Write ){
    style_submenu_element("Artifact Stats", "artifact_stats");
  }
  if( !unpubOnly && mx>n && P("s")==0 ){
    int i;
    @ <p>Select a range of artifacts to view:</p>
    @ <ul>
    for(i=1; i<=mx; i+=n){
      @ <li> %z(href("%R/bloblist?s=%d&n=%d",i,n))
      @ %d(i)..%d(i+n-1<mx?i+n-1:mx)</a>
    }
    @ </ul>
    style_footer();
    return;
  }
  if( !unpubOnly && mx>n ){
    style_submenu_element("Index", "bloblist");
  }
  if( unpubOnly ){
    zRange = mprintf("IN private");


  }else{
    zRange = mprintf("BETWEEN %d AND %d", s, s+n-1);
  }
  describe_artifacts(zRange);
  fossil_free(zRange);
  db_prepare(&q,
    "SELECT rid, uuid, summary, isPrivate FROM description ORDER BY rid"

  );
  if( skin_detail_boolean("white-foreground") ){
    zSha1Bg = "#714417";
    zSha3Bg = "#177117";
  }else{
    zSha1Bg = "#ebffb0";
    zSha3Bg = "#b0ffb0";
  }
  @ <table cellpadding="0" cellspacing="0">





  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q,0);
    const char *zUuid = db_column_text(&q, 1);
    const char *zDesc = db_column_text(&q, 2);
    int isPriv = db_column_int(&q,3);






    if( hashClr ){
      const char *zClr = db_column_bytes(&q,1)>40 ? zSha3Bg : zSha1Bg;
      @ <tr style='background-color:%s(zClr);'><td align="right">%d(rid)</td>
    }else{
      @ <tr><td align="right">%d(rid)</td>
    }
    @ <td>&nbsp;%z(href("%R/info/%!S",zUuid))%S(zUuid)</a>&nbsp;</td>








    @ <td align="left">%h(zDesc)</td>






    if( isPriv ){







      @ <td>(unpublished)</td>
    }
    @ </tr>
  }
  @ </table>
  db_finalize(&q);






































































  style_footer();
}

/*
** WEBPAGE: bigbloblist
**
** Return a page showing the largest artifacts in the repository in order







|
>







|
>











>
>
>
>
>
>
>
>
>
>




|











|


|

>
>






|
>








|
>
>
>
>
>





>
>
>
>
>
>







>
>
>
>
>
>
>
>

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





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







1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
/*
** WEBPAGE: bloblist
**
** Return a page showing all artifacts in the repository.  Query parameters:
**
**   n=N         Show N artifacts
**   s=S         Start with artifact number S
**   priv        Show only unpublished or private artifacts
**   phan        Show only phantom artifacts
**   hclr        Color code hash types (SHA1 vs SHA3)
*/
void bloblist_page(void){
  Stmt q;
  int s = atoi(PD("s","0"));
  int n = atoi(PD("n","5000"));
  int mx = db_int(0, "SELECT max(rid) FROM blob");
  int privOnly = PB("priv");
  int phantomOnly = PB("phan");
  int hashClr = PB("hclr");
  char *zRange;
  char *zSha1Bg;
  char *zSha3Bg;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_header("List Of Artifacts");
  style_submenu_element("250 Largest", "bigbloblist");
  if( g.perm.Admin ){
    style_submenu_element("Artifact Log", "rcvfromlist");
  }
  if( !phantomOnly ){
    style_submenu_element("Phantoms", "bloblist?phan");
  }
  if( g.perm.Private || g.perm.Admin ){
    if( !privOnly ){
      style_submenu_element("Private", "bloblist?priv");
    }
  }else{
    privOnly = 0;
  }
  if( g.perm.Write ){
    style_submenu_element("Artifact Stats", "artifact_stats");
  }
  if( !privOnly && !phantomOnly && mx>n && P("s")==0 ){
    int i;
    @ <p>Select a range of artifacts to view:</p>
    @ <ul>
    for(i=1; i<=mx; i+=n){
      @ <li> %z(href("%R/bloblist?s=%d&n=%d",i,n))
      @ %d(i)..%d(i+n-1<mx?i+n-1:mx)</a>
    }
    @ </ul>
    style_footer();
    return;
  }
  if( phantomOnly || privOnly || mx>n ){
    style_submenu_element("Index", "bloblist");
  }
  if( privOnly ){
    zRange = mprintf("IN private");
  }else if( phantomOnly ){
    zRange = mprintf("IN phantom");
  }else{
    zRange = mprintf("BETWEEN %d AND %d", s, s+n-1);
  }
  describe_artifacts(zRange);
  fossil_free(zRange);
  db_prepare(&q,
    "SELECT rid, uuid, summary, isPrivate, type='phantom', rcvid, ref"
    "  FROM description ORDER BY rid"
  );
  if( skin_detail_boolean("white-foreground") ){
    zSha1Bg = "#714417";
    zSha3Bg = "#177117";
  }else{
    zSha1Bg = "#ebffb0";
    zSha3Bg = "#b0ffb0";
  }
  @ <table cellpadding="2" cellspacing="0" border="1">
  if( g.perm.Admin ){
    @ <tr><th>RID<th>Hash<th>Rcvid<th>Description<th>Ref<th>Remarks
  }else{
    @ <tr><th>RID<th>Hash<th>Description<th>Ref<th>Remarks
  }
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q,0);
    const char *zUuid = db_column_text(&q, 1);
    const char *zDesc = db_column_text(&q, 2);
    int isPriv = db_column_int(&q,3);
    int isPhantom = db_column_int(&q,4);
    const char *zRef = db_column_text(&q,6);
    if( isPriv && !isPhantom && !g.perm.Private && !g.perm.Admin ){
      /* Don't show private artifacts to users without Private (x) permission */
      continue;
    }
    if( hashClr ){
      const char *zClr = db_column_bytes(&q,1)>40 ? zSha3Bg : zSha1Bg;
      @ <tr style='background-color:%s(zClr);'><td align="right">%d(rid)</td>
    }else{
      @ <tr><td align="right">%d(rid)</td>
    }
    @ <td>&nbsp;%z(href("%R/info/%!S",zUuid))%S(zUuid)</a>&nbsp;</td>
    if( g.perm.Admin ){
      int rcvid = db_column_int(&q,5);
      if( rcvid<=0 ){
        @ <td>&nbsp;
      }else{
        @ <td><a href='%R/rcvfrom?rcvid=%d(rcvid)'>%d(rcvid)</a>
      }
    }
    @ <td align="left">%h(zDesc)</td>
    if( zRef && zRef[0] ){
      @ <td>%z(href("%R/info/%!S",zRef))%S(zRef)</a>
    }else{
      @ <td>&nbsp;
    }
    if( isPriv || isPhantom ){
      if( isPriv==0 ){
        @ <td>phantom</td>
      }else if( isPhantom==0 ){
        @ <td>private</td>
      }else{
        @ <td>private,phantom</td>
      }
    }else{
      @ <td>&nbsp;
    }
    @ </tr>
  }
  @ </table>
  db_finalize(&q);
  style_footer();
}

/*
** Output HTML that shows a table of all public phantoms.
*/
void table_of_public_phantoms(void){
  Stmt q;
  char *zRange;
  zRange = mprintf("IN (SELECT rid FROM phantom EXCEPT"
                   " SELECT rid FROM private)");
  describe_artifacts(zRange);
  fossil_free(zRange);
  db_prepare(&q,
    "SELECT rid, uuid, summary, ref"
    "  FROM description ORDER BY rid"
  );
  @ <table cellpadding="2" cellspacing="0" border="1">
  @ <tr><th>RID<th>Description<th>Source
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q,0);
    const char *zUuid = db_column_text(&q, 1);
    const char *zDesc = db_column_text(&q, 2);
    const char *zRef = db_column_text(&q,3);
    @ <tr><td valign="top">%d(rid)</td>
    @ <td valign="top" align="left">%h(zUuid)<br>%h(zDesc)</td>
    if( zRef && zRef[0] ){
      @ <td valign="top">%z(href("%R/info/%!S",zRef))%!S(zRef)</a>
    }else{
      @ <td>&nbsp;
    }
    @ </tr>
  }
  @ </table>
  db_finalize(&q);
}

/*
** WEBPAGE: phantoms
**
** Show a list of all "phantom" artifacts that are not marked as "private".
**
** A "phantom" artifact is an artifact whose hash named appears in some
** artifact but whose content is unknown.  For example, if a manifest
** references a particular SHA3 hash of a file, but that SHA3 hash is
** not on the shunning list and is not in the database, then the file
** is a phantom.  We know it exists, but we do not know its content.
**
** Whenever a sync occurs, both each party looks at its phantom list
** and for every phantom that is not also marked private, it asks the
** other party to send it the content.  This mechanism helps keep all
** repositories synced up.
**
** This page is similar to the /bloblist page in that it lists artifacts.
** But this page is a special case in that it only shows phantoms that
** are not private.  In other words, this page shows all phantoms that
** generate extra network traffic on every sync request.
*/
void phantom_list_page(void){
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_header("Public Phantom Artifacts");
  if( g.perm.Admin ){
    style_submenu_element("Artifact Log", "rcvfromlist");
    style_submenu_element("Artifact List", "bloblist");
  }
  if( g.perm.Write ){
    style_submenu_element("Artifact Stats", "artifact_stats");
  }
  table_of_public_phantoms();
  style_footer();
}

/*
** WEBPAGE: bigbloblist
**
** Return a page showing the largest artifacts in the repository in order
Changes to src/printf.c.
202
203
204
205
206
207
208



209
210
211
212
213

214
215
216
217
218
219
220

/*
** Find the length of a string as long as that length does not
** exceed N bytes.  If no zero terminator is seen in the first
** N bytes then return N.  If N is negative, then this routine
** is an alias for strlen().
*/



static int StrNLen32(const char *z, int N){
  int n = 0;
  while( (N-- != 0) && *(z++)!=0 ){ n++; }
  return n;
}


/*
** Return an appropriate set of flags for wiki_convert() for displaying
** comments on a timeline.  These flag settings are determined by
** configuration parameters.
**
** The altForm2 argument is true for "%!W" (with the "!" alternate-form-2







>
>
>





>







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224

/*
** Find the length of a string as long as that length does not
** exceed N bytes.  If no zero terminator is seen in the first
** N bytes then return N.  If N is negative, then this routine
** is an alias for strlen().
*/
#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
# define StrNLen32(Z,N) (int)strnlen(Z,N)
#else
static int StrNLen32(const char *z, int N){
  int n = 0;
  while( (N-- != 0) && *(z++)!=0 ){ n++; }
  return n;
}
#endif

/*
** Return an appropriate set of flags for wiki_convert() for displaying
** comments on a timeline.  These flag settings are determined by
** configuration parameters.
**
** The altForm2 argument is true for "%!W" (with the "!" alternate-form-2
Changes to src/rebuild.c.
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205







206
207
208
209
210
211
212
  );
}

/*
** Variables used to store state information about an on-going "rebuild"
** or "deconstruct".
*/
static int totalSize;       /* Total number of artifacts to process */
static int processCnt;      /* Number processed so far */
static int ttyOutput;       /* Do progress output */
static Bag bagDone;         /* Bag of records rebuilt */

static char *zFNameFormat;  /* Format string for filenames on deconstruct */
static int cchFNamePrefix;  /* Length of directory prefix in zFNameFormat */
static char *zDestDir;      /* Destination directory on deconstruct */
static int prefixLength;    /* Length of directory prefix for deconstruct */
static int fKeepRid1;       /* Flag to preserve RID=1 on de- and reconstruct */


/*
** Draw the percent-complete message.
** The input is actually the permill complete.
*/
static void percent_complete(int permill){
  static int lastOutput = -1;
  if( permill>lastOutput ){
    fossil_print("  %d.%d%% complete...\r", permill/10, permill%10);
    fflush(stdout);
    lastOutput = permill;
  }
}









/*
** Called after each artifact is processed
*/
static void rebuild_step_done(int rid){
  /* assert( bag_find(&bagDone, rid)==0 ); */
  bag_insert(&bagDone, rid);







|
|
|
|



|

















>
>
>
>
>
>
>







174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  );
}

/*
** Variables used to store state information about an on-going "rebuild"
** or "deconstruct".
*/
static int totalSize;          /* Total number of artifacts to process */
static int processCnt;         /* Number processed so far */
static int ttyOutput;          /* Do progress output */
static Bag bagDone = Bag_INIT; /* Bag of records rebuilt */

static char *zFNameFormat;  /* Format string for filenames on deconstruct */
static int cchFNamePrefix;  /* Length of directory prefix in zFNameFormat */
static const char *zDestDir;/* Destination directory on deconstruct */
static int prefixLength;    /* Length of directory prefix for deconstruct */
static int fKeepRid1;       /* Flag to preserve RID=1 on de- and reconstruct */


/*
** Draw the percent-complete message.
** The input is actually the permill complete.
*/
static void percent_complete(int permill){
  static int lastOutput = -1;
  if( permill>lastOutput ){
    fossil_print("  %d.%d%% complete...\r", permill/10, permill%10);
    fflush(stdout);
    lastOutput = permill;
  }
}

/*
** Frees rebuild-level cached state. Intended only to be called by the
** app-level atexit() handler.
*/
void rebuild_clear_cache(){
  bag_clear(&bagDone);
}

/*
** Called after each artifact is processed
*/
static void rebuild_step_done(int rid){
  /* assert( bag_find(&bagDone, rid)==0 ); */
  bag_insert(&bagDone, rid);
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
*/
int rebuild_db(int randomize, int doOut, int doClustering){
  Stmt s, q;
  int errCnt = 0;
  int incrSize;
  Blob sql;

  bag_init(&bagDone);
  ttyOutput = doOut;
  processCnt = 0;
  if (ttyOutput && !g.fQuiet) {
    percent_complete(0);
  }
  alert_triggers_disable();
  rebuild_update_schema();







|







371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
*/
int rebuild_db(int randomize, int doOut, int doClustering){
  Stmt s, q;
  int errCnt = 0;
  int incrSize;
  Blob sql;

  bag_clear(&bagDone);
  ttyOutput = doOut;
  processCnt = 0;
  if (ttyOutput && !g.fQuiet) {
    percent_complete(0);
  }
  alert_triggers_disable();
  rebuild_update_schema();
1131
1132
1133
1134
1135
1136
1137
1138
1139














































1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151


1152
1153
1154
1155
1156

1157

1158
1159
1160
1161
1162
1163
1164
    zFile,zHashPolicy);
  free(zFile);
  free(zFNameFormat);
  zFNameFormat = 0;
  cchFNamePrefix = 0;
}
#endif

/*














































** COMMAND: reconstruct*
**
** Usage: %fossil reconstruct ?OPTIONS? FILENAME DIRECTORY
**
** This command studies the artifacts (files) in DIRECTORY and
** reconstructs the fossil record from them. It places the new
** fossil repository in FILENAME. Subdirectories are read, files
** with leading '.' in the filename are ignored.
**
** Options:
**    -K|--keep-rid1    Read the filename of the artifact with
**                      RID=1 from the file .rid in DIRECTORY.


**
** See also: deconstruct, rebuild
*/
void reconstruct_cmd(void) {
  char *zPassword;

  fKeepRid1 = find_option("keep-rid1","K",0)!=0;

  if( g.argc!=4 ){
    usage("FILENAME DIRECTORY");
  }
  if( file_isdir(g.argv[3], ExtFILE)!=1 ){
    fossil_print("\"%s\" is not a directory\n\n", g.argv[3]);
    usage("FILENAME DIRECTORY");
  }









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




|
|
<
|


|
|
>
>





>

>







1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198

1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
    zFile,zHashPolicy);
  free(zFile);
  free(zFNameFormat);
  zFNameFormat = 0;
  cchFNamePrefix = 0;
}
#endif

/*
** Helper functions used by the `deconstruct' and `reconstruct' commands to
** save and restore the contents of the PRIVATE table.
*/
void private_export(char *zFileName)
{
  Stmt q;
  Blob fctx = empty_blob;
  blob_append(&fctx, "# The UUIDs of private artifacts\n", -1);
  db_prepare(&q,
    "SELECT uuid FROM blob WHERE rid IN ( SELECT rid FROM private );");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zUuid = db_column_text(&q, 0);
    blob_append(&fctx, zUuid, -1);
    blob_append(&fctx, "\n", -1);
  }
  db_finalize(&q);
  blob_write_to_file(&fctx, zFileName);
  blob_reset(&fctx);
}
void private_import(char *zFileName)
{
  Blob fctx;
  if( blob_read_from_file(&fctx, zFileName, ExtFILE)!=-1 ){
    Blob line, value;
    while( blob_line(&fctx, &line)>0 ){
      char *zUuid;
      int nUuid;
      if( blob_token(&line, &value)==0 ) continue;  /* Empty line */
      if( blob_buffer(&value)[0]=='#' ) continue;   /* Comment */
      blob_trim(&value);
      zUuid = blob_buffer(&value);
      nUuid = blob_size(&value);
      zUuid[nUuid] = 0;
      if( hname_validate(zUuid, nUuid)!=HNAME_ERROR ){
        canonical16(zUuid, nUuid);
        db_multi_exec(
          "INSERT OR IGNORE INTO private"
          " SELECT rid FROM blob WHERE uuid = %Q;",
          zUuid);
      }
    }
    blob_reset(&fctx);
  }
}

/*
** COMMAND: reconstruct*
**
** Usage: %fossil reconstruct ?OPTIONS? FILENAME DIRECTORY
**
** This command studies the artifacts (files) in DIRECTORY and reconstructs the
** Fossil record from them.  It places the new Fossil repository in FILENAME.

** Subdirectories are read, files with leading '.' in the filename are ignored.
**
** Options:
**   -K|--keep-rid1     Read the filename of the artifact with RID=1 from the
**                      file .rid in DIRECTORY.
**   -P|--keep-private  Mark the artifacts listed in the file .private in
**                      DIRECTORY as private in the new Fossil repository.
**
** See also: deconstruct, rebuild
*/
void reconstruct_cmd(void) {
  char *zPassword;
  int fKeepPrivate;
  fKeepRid1 = find_option("keep-rid1","K",0)!=0;
  fKeepPrivate = find_option("keep-private","P",0)!=0;
  if( g.argc!=4 ){
    usage("FILENAME DIRECTORY");
  }
  if( file_isdir(g.argv[3], ExtFILE)!=1 ){
    fossil_print("\"%s\" is not a directory\n\n", g.argv[3]);
    usage("FILENAME DIRECTORY");
  }
1173
1174
1175
1176
1177
1178
1179


1180






1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214



1215
1216
1217
1218
1219
1220
1221

1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237


1238
1239
1240
1241
1242
1243
1244
  db_initial_setup(0, 0, 0);

  fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]);
  recon_read_dir(g.argv[3]);
  fossil_print("\nBuilding the Fossil repository...\n");

  rebuild_db(0, 1, 1);


  reconstruct_private_table();







  /* Skip the verify_before_commit() step on a reconstruct.  Most artifacts
  ** will have been changed and verification therefore takes a really, really
  ** long time.
  */
  verify_cancel();

  db_end_transaction(0);
  fossil_print("project-id: %s\n", db_get("project-code", 0));
  fossil_print("server-id: %s\n", db_get("server-code", 0));
  zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
  fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword);
}

/*
** COMMAND: deconstruct*
**
** Usage %fossil deconstruct ?OPTIONS? DESTINATION
**
**
** This command exports all artifacts of a given repository and
** writes all artifacts to the file system. The DESTINATION directory
** will be populated with subdirectories AA and files AA/BBBBBBBBB.., where
** AABBBBBBBBB.. is the 40+ character artifact ID, AA the first 2 characters.
** 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.
**   -K|--keep-rid1              Save the filename of the artifact with RID=1 to
**                               the file .rid1 in the DESTINATION directory.
**   -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 *zPrefixOpt;
  Stmt        s;
  int privateFlag;


  fKeepRid1 = find_option("keep-rid1","K",0)!=0;
  /* 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 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];







>
>

>
>
>
>
>
>



















<
|
|
|
|
|
|








>
>
>

|





>
















>
>







1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263

1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
  db_initial_setup(0, 0, 0);

  fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]);
  recon_read_dir(g.argv[3]);
  fossil_print("\nBuilding the Fossil repository...\n");

  rebuild_db(0, 1, 1);

  /* Backwards compatibility: Mark check-ins with "+private" tags as private. */
  reconstruct_private_table();
  /* Newer method: Import the list of private artifacts to the PRIVATE table. */
  if( fKeepPrivate ){
    char *zFnDotPrivate = mprintf("%s/.private", g.argv[3]);
    private_import(zFnDotPrivate);
    free(zFnDotPrivate);
  }

  /* Skip the verify_before_commit() step on a reconstruct.  Most artifacts
  ** will have been changed and verification therefore takes a really, really
  ** long time.
  */
  verify_cancel();

  db_end_transaction(0);
  fossil_print("project-id: %s\n", db_get("project-code", 0));
  fossil_print("server-id: %s\n", db_get("server-code", 0));
  zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
  fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword);
}

/*
** COMMAND: deconstruct*
**
** Usage %fossil deconstruct ?OPTIONS? DESTINATION
**

** This command exports all artifacts of a given repository and writes all
** artifacts to the file system.  The DESTINATION directory will be populated
** with subdirectories AA and files AA/BBBBBBBBB.., where AABBBBBBBBB.. is the
** 40+ character artifact ID, AA the first 2 characters.
** 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.
**   -K|--keep-rid1              Save the filename of the artifact with RID=1 to
**                               the file .rid1 in the DESTINATION directory.
**   -L|--prefixlength N         Set the length of the names of the DESTINATION
**                               subdirectories to N.
**   --private                   Include private artifacts.
**   -P|--keep-private           Save the list of private artifacts to the file
**                               .private in the DESTINATION directory (implies
**                               the --private option).
**
** See also: reconstruct, rebuild
*/
void deconstruct_cmd(void){
  const char *zPrefixOpt;
  Stmt        s;
  int privateFlag;
  int fKeepPrivate;

  fKeepRid1 = find_option("keep-rid1","K",0)!=0;
  /* 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 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;
  fKeepPrivate = find_option("keep-private","P",0)!=0;
  if( fKeepPrivate ) privateFlag = 1;
  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];
1298
1299
1300
1301
1302
1303
1304








1305
1306
1307
1308
1309
1310
1311
1312
        Blob content;
        content_get(rid, &content);
        rebuild_step(rid, size, &content);
      }
    }
  }
  db_finalize(&s);








  if(!g.fQuiet && ttyOutput ){
    fossil_print("\n");
  }

  /* free filename format string */
  free(zFNameFormat);
  zFNameFormat = 0;
}







>
>
>
>
>
>
>
>








1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
        Blob content;
        content_get(rid, &content);
        rebuild_step(rid, size, &content);
      }
    }
  }
  db_finalize(&s);

  /* Export the list of private artifacts. */
  if( fKeepPrivate ){
    char *zFnDotPrivate = mprintf("%s/.private", zDestDir);
    private_export(zFnDotPrivate);
    free(zFnDotPrivate);
  }

  if(!g.fQuiet && ttyOutput ){
    fossil_print("\n");
  }

  /* free filename format string */
  free(zFNameFormat);
  zFNameFormat = 0;
}
Changes to src/regexp.c.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
      c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
      if( c<0x80 ) c = 0xfffd;
    }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
           && (p->z[p->i+1]&0xc0)==0x80 ){
      c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
      p->i += 2;
      if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
    }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
           && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
      c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
                       | (p->z[p->i+2]&0x3f);
      p->i += 3;
      if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
    }else{







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
      c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
      if( c<0x80 ) c = 0xfffd;
    }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
           && (p->z[p->i+1]&0xc0)==0x80 ){
      c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
      p->i += 2;
      if( c<=0x7ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
    }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
           && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
      c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
                       | (p->z[p->i+2]&0x3f);
      p->i += 3;
      if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
    }else{
Changes to src/repolist.c.
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
** processing is disallowed for chroot jails because g.zRepositoryName
** is always "/" inside a chroot jail and so it cannot be used as a flag
** to signal the special processing in that case.  The special case
** processing is intended for the "fossil all ui" command which never
** runs in a chroot jail anyhow.
**
** Or, if no repositories can be located beneath g.zRepositoryName,
** return 0.
*/
int repo_list_page(void){
  Blob base;           /* document root for all repositories */
  int n = 0;           /* Number of repositories found */
  int allRepo;         /* True if running "fossil ui all".
                       ** False if a directory scan of base for repos */
  Blob html;           /* Html for the body of the repository list */







|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
** processing is disallowed for chroot jails because g.zRepositoryName
** is always "/" inside a chroot jail and so it cannot be used as a flag
** to signal the special processing in that case.  The special case
** processing is intended for the "fossil all ui" command which never
** runs in a chroot jail anyhow.
**
** Or, if no repositories can be located beneath g.zRepositoryName,
** close g.db and return 0.
*/
int repo_list_page(void){
  Blob base;           /* document root for all repositories */
  int n = 0;           /* Number of repositories found */
  int allRepo;         /* True if running "fossil ui all".
                       ** False if a directory scan of base for repos */
  Blob html;           /* Html for the body of the repository list */
138
139
140
141
142
143
144

145
146
147
148
149
150
151
    vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
    db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
    allRepo = 0;
  }
  n = db_int(0, "SELECT count(*) FROM sfile");
  if( n==0 ){
    sqlite3_close(g.db);

    return 0;
  }else{
    Stmt q;
    double rNow;
    blob_append_sql(&html,
      "<table border='0' class='sortable' data-init-sort='1'"
      " data-column-types='txtxk'><thead>\n"







>







138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
    db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
    allRepo = 0;
  }
  n = db_int(0, "SELECT count(*) FROM sfile");
  if( n==0 ){
    sqlite3_close(g.db);
    g.db = 0;
    return 0;
  }else{
    Stmt q;
    double rNow;
    blob_append_sql(&html,
      "<table border='0' class='sortable' data-init-sort='1'"
      " data-column-types='txtxk'><thead>\n"
Changes to src/rss.c.
24
25
26
27
28
29
30
31
32

33
34
35
36
37
38
39

/*
** WEBPAGE: timeline.rss
** URL:  /timeline.rss?y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME
**
** Produce an RSS feed of the timeline.
**
** TYPE may be: all, ci (show check-ins only), t (show tickets only),
** w (show wiki only).

**
** LIMIT is the number of items to show.
**
** tkt=UUID filters for only those events for the specified ticket. tag=TAG
** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
**
** In addition, name=FILENAME filters for a specific file. This may be







|
|
>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

/*
** WEBPAGE: timeline.rss
** URL:  /timeline.rss?y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME
**
** Produce an RSS feed of the timeline.
**
** TYPE may be: all, ci (show check-ins only), t (show ticket changes only),
** w (show wiki only), e (show tech notes only), f (show forum posts only),
** g (show tag/branch changes only).
**
** LIMIT is the number of items to show.
**
** tkt=UUID filters for only those events for the specified ticket. tag=TAG
** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
**
** In addition, name=FILENAME filters for a specific file. This may be
Changes to src/schema.c.
156
157
158
159
160
161
162






163
164
165
166
167
168
169
@   mtime DATE,           -- When added.  seconds since 1970
@   scom TEXT             -- Optional text explaining why the shun occurred
@ );
@
@ -- Artifacts that should not be pushed are stored in the "private"
@ -- table.  Private artifacts are omitted from the "unclustered" and
@ -- "unsent" tables.






@ --
@ CREATE TABLE private(rid INTEGER PRIMARY KEY);
@
@ -- An entry in this table describes a database query that generates a
@ -- table of tickets.
@ --
@ CREATE TABLE reportfmt(







>
>
>
>
>
>







156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
@   mtime DATE,           -- When added.  seconds since 1970
@   scom TEXT             -- Optional text explaining why the shun occurred
@ );
@
@ -- Artifacts that should not be pushed are stored in the "private"
@ -- table.  Private artifacts are omitted from the "unclustered" and
@ -- "unsent" tables.
@ --
@ -- A phantom artifact (that is, an artifact with BLOB.SIZE<0 - an artifact
@ -- for which we do not know the content) might also be marked as private.
@ -- This comes about when an artifact is named in a manifest or tag but
@ -- the content of that artifact is held privately by some other peer
@ -- repository.
@ --
@ CREATE TABLE private(rid INTEGER PRIMARY KEY);
@
@ -- An entry in this table describes a database query that generates a
@ -- table of tickets.
@ --
@ CREATE TABLE reportfmt(
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
@ -- When a hyperlink occurs from one artifact to another (for example
@ -- when a check-in comment refers to a ticket) an entry is made in
@ -- the following table for that hyperlink.  This table is used to
@ -- facilitate the display of "back links".
@ --
@ CREATE TABLE backlink(
@   target TEXT,           -- Where the hyperlink points to
@   srctype INT,           -- 0: check-in  1: ticket  2: wiki
@   srcid INT,             -- rid for check-in or wiki.  tkt_id for ticket.
@   mtime TIMESTAMP,       -- time that the hyperlink was added. Julian day.
@   UNIQUE(target, srctype, srcid)
@ );
@ CREATE INDEX backlink_src ON backlink(srcid, srctype);
@
@ -- Each attachment is an entry in the following table.  Only
@ -- the most recent attachment (identified by the D card) is saved.







|
|







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
@ -- When a hyperlink occurs from one artifact to another (for example
@ -- when a check-in comment refers to a ticket) an entry is made in
@ -- the following table for that hyperlink.  This table is used to
@ -- facilitate the display of "back links".
@ --
@ CREATE TABLE backlink(
@   target TEXT,           -- Where the hyperlink points to
@   srctype INT,           -- 0=comment 1=ticket 2=wiki. See BKLNK_* below.
@   srcid INT,             -- EVENT.OBJID for the source document
@   mtime TIMESTAMP,       -- time that the hyperlink was added. Julian day.
@   UNIQUE(target, srctype, srcid)
@ );
@ CREATE INDEX backlink_src ON backlink(srcid, srctype);
@
@ -- Each attachment is an entry in the following table.  Only
@ -- the most recent attachment (identified by the D card) is saved.
468
469
470
471
472
473
474












475
476
477
478
479
480
481
@   childid INT,
@   isExclude BOOLEAN DEFAULT false,
@   PRIMARY KEY(parentid, childid)
@ ) WITHOUT ROWID;
@ CREATE INDEX cherrypick_cid ON cherrypick(childid);
;













/*
** Predefined tagid values
*/
#if INTERFACE
# define TAG_BGCOLOR    1     /* Set the background color for display */
# define TAG_COMMENT    2     /* The check-in comment */
# define TAG_USER       3     /* User who made a checking */







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







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
@   childid INT,
@   isExclude BOOLEAN DEFAULT false,
@   PRIMARY KEY(parentid, childid)
@ ) WITHOUT ROWID;
@ CREATE INDEX cherrypick_cid ON cherrypick(childid);
;

/*
** Allowed values for backlink.srctype
*/
#if INTERFACE
# define BKLNK_COMMENT    0   /* Check-in comment */
# define BKLNK_TICKET     1   /* Ticket body or title */
# define BKLNK_WIKI       2   /* Wiki */
# define BKLNK_EVENT      3   /* Technote */
# define BKLNK_FORUM      4   /* Forum post */
# define ValidBklnk(X)   (X>=0 && X<=4)  /* True if backlink.srctype is valid */
#endif

/*
** Predefined tagid values
*/
#if INTERFACE
# define TAG_BGCOLOR    1     /* Set the background color for display */
# define TAG_COMMENT    2     /* The check-in comment */
# define TAG_USER       3     /* User who made a checking */
Changes to src/search.c.
12
13
14
15
16
17
18
19

20
21
22
23
24
25
26
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to implement a search functions
** against timeline comments, check-in content, wiki pages, and/or tickets.

**
** The search can be either a per-query "grep"-like search that scans
** the entire corpus.  Or it can use the FTS4 or FTS5 search engine of
** SQLite.  The choice is a administrator configuration option.
**
** The first option is referred to as "full-scan search".  The second
** option is called "indexed search".







|
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to implement a search functions
** against timeline comments, check-in content, wiki pages, tickets,
** and/or forum posts.
**
** The search can be either a per-query "grep"-like search that scans
** the entire corpus.  Or it can use the FTS4 or FTS5 search engine of
** SQLite.  The choice is a administrator configuration option.
**
** The first option is referred to as "full-scan search".  The second
** option is called "indexed search".
329
330
331
332
333
334
335








336
337
338
339
340
341
342
/*
** COMMAND: test-match
**
** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ...
**
** Run the full-scan search algorithm using SEARCHSTRING against
** the text of the files listed.  Output matches and snippets.








*/
void test_match_cmd(void){
  Search *p;
  int i;
  Blob x;
  int score;
  char *zDoc;







>
>
>
>
>
>
>
>







330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/*
** COMMAND: test-match
**
** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ...
**
** Run the full-scan search algorithm using SEARCHSTRING against
** the text of the files listed.  Output matches and snippets.
**
** Options:
**
**    --begin TEXT        Text to insert before each match
**    --end TEXT          Text to insert after each match
**    --gap TEXT          Text to indicate elided content
**    --html              Input is HTML
**    --static            Use the static Search object
*/
void test_match_cmd(void){
  Search *p;
  int i;
  Blob x;
  int score;
  char *zDoc;
370
371
372
373
374
375
376
377

378
379
380
381
382
383
384
**
**     search_init(PATTERN,BEGIN,END,GAP,FLAGS)
**
** All arguments are optional.  PATTERN is the search pattern.  If it
** is omitted, then the global search pattern is reset.  BEGIN and END
** and GAP are the strings used to construct snippets.  FLAGS is an
** integer bit pattern containing the various SRCH_CKIN, SRCH_DOC,
** SRCH_TKT, or SRCH_ALL bits to determine what is to be searched.

*/
static void search_init_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zPattern = 0;







|
>







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
**
**     search_init(PATTERN,BEGIN,END,GAP,FLAGS)
**
** All arguments are optional.  PATTERN is the search pattern.  If it
** is omitted, then the global search pattern is reset.  BEGIN and END
** and GAP are the strings used to construct snippets.  FLAGS is an
** integer bit pattern containing the various SRCH_CKIN, SRCH_DOC,
** SRCH_TKT, SRCH_FORUM, or SRCH_ALL bits to determine what is to be
** searched.
*/
static void search_init_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zPattern = 0;
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  }
}

/*     search_match(TEXT, TEXT, ....)
**
** Using the full-scan search engine created by the most recent call
** to search_init(), match the input the TEXT arguments.
** Remember the results global full-scan search object.
** Return non-zero on a match and zero on a miss.
*/
static void search_match_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){







|







415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  }
}

/*     search_match(TEXT, TEXT, ....)
**
** Using the full-scan search engine created by the most recent call
** to search_init(), match the input the TEXT arguments.
** Remember the results in the global full-scan search object.
** Return non-zero on a match and zero on a miss.
*/
static void search_match_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
528
529
530
531
532
533
534

535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563





564
565
566
567
568
569
570

/*
** Register the various SQL functions (defined above) needed to implement
** full-scan search.
*/
void search_sql_setup(sqlite3 *db){
  static int once = 0;

  if( once++ ) return;
  sqlite3_create_function(db, "search_match", -1, SQLITE_UTF8, 0,
     search_match_sqlfunc, 0, 0);
  sqlite3_create_function(db, "search_score", 0, SQLITE_UTF8, 0,
     search_score_sqlfunc, 0, 0);
  sqlite3_create_function(db, "search_snippet", 0, SQLITE_UTF8, 0,
     search_snippet_sqlfunc, 0, 0);
  sqlite3_create_function(db, "search_init", -1, SQLITE_UTF8, 0,
     search_init_sqlfunc, 0, 0);
  sqlite3_create_function(db, "stext", 3, SQLITE_UTF8, 0,
     search_stext_sqlfunc, 0, 0);
  sqlite3_create_function(db, "title", 3, SQLITE_UTF8, 0,
     search_title_sqlfunc, 0, 0);
  sqlite3_create_function(db, "body", 3, SQLITE_UTF8, 0,
     search_body_sqlfunc, 0, 0);
  sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
     search_urlencode_sqlfunc, 0, 0);
}

/*
** Testing the search function.
**
** COMMAND: search*
**
** Usage: %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern...
**
** Search for timeline entries matching all words provided on the
** command line. Whole-word matches scope more highly than partial
** matches.





**
** Outputs, by default, some top-N fraction of the results. The -all
** option can be used to output all matches, regardless of their search
** score.  The -limit option can be used to limit the number of entries
** returned.  The -width option can be used to set the output width used
** when printing matches.
**







>

|

|

|

|

|

|

|

|













>
>
>
>
>







538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586

/*
** Register the various SQL functions (defined above) needed to implement
** full-scan search.
*/
void search_sql_setup(sqlite3 *db){
  static int once = 0;
  static const int enc = SQLITE_UTF8|SQLITE_INNOCUOUS;
  if( once++ ) return;
  sqlite3_create_function(db, "search_match", -1, enc, 0,
     search_match_sqlfunc, 0, 0);
  sqlite3_create_function(db, "search_score", 0, enc, 0,
     search_score_sqlfunc, 0, 0);
  sqlite3_create_function(db, "search_snippet", 0, enc, 0,
     search_snippet_sqlfunc, 0, 0);
  sqlite3_create_function(db, "search_init", -1, enc, 0,
     search_init_sqlfunc, 0, 0);
  sqlite3_create_function(db, "stext", 3, enc, 0,
     search_stext_sqlfunc, 0, 0);
  sqlite3_create_function(db, "title", 3, enc, 0,
     search_title_sqlfunc, 0, 0);
  sqlite3_create_function(db, "body", 3, enc, 0,
     search_body_sqlfunc, 0, 0);
  sqlite3_create_function(db, "urlencode", 1, enc, 0,
     search_urlencode_sqlfunc, 0, 0);
}

/*
** Testing the search function.
**
** COMMAND: search*
**
** Usage: %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern...
**
** Search for timeline entries matching all words provided on the
** command line. Whole-word matches scope more highly than partial
** matches.
**
** Note:  The command only search the EVENT table.  So it will only
** display check-in comments or other comments that appear on an
** unaugmented timeline.  It does not search document text or forum
** messages.
**
** Outputs, by default, some top-N fraction of the results. The -all
** option can be used to output all matches, regardless of their search
** score.  The -limit option can be used to limit the number of entries
** returned.  The -width option can be used to set the output width used
** when printing matches.
**
642
643
644
645
646
647
648
649

650
651
652
653
654
655
656
#define SRCH_TECHNOTE 0x0010    /* Search over tech notes */
#define SRCH_FORUM    0x0020    /* Search over forum messages */
#define SRCH_ALL      0x003f    /* Search over everything */
#endif

/*
** Remove bits from srchFlags which are disallowed by either the
** current server configuration or by user permissions.

*/
unsigned int search_restrict(unsigned int srchFlags){
  static unsigned int knownGood = 0;
  static unsigned int knownBad = 0;
  static const struct { unsigned m; const char *zKey; } aSetng[] = {
     { SRCH_CKIN,     "search-ci"   },
     { SRCH_DOC,      "search-doc"  },







|
>







658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
#define SRCH_TECHNOTE 0x0010    /* Search over tech notes */
#define SRCH_FORUM    0x0020    /* Search over forum messages */
#define SRCH_ALL      0x003f    /* Search over everything */
#endif

/*
** Remove bits from srchFlags which are disallowed by either the
** current server configuration or by user permissions.  Return
** the revised search flags mask.
*/
unsigned int search_restrict(unsigned int srchFlags){
  static unsigned int knownGood = 0;
  static unsigned int knownBad = 0;
  static const struct { unsigned m; const char *zKey; } aSetng[] = {
     { SRCH_CKIN,     "search-ci"   },
     { SRCH_DOC,      "search-doc"  },
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
*/
static void search_indexed(
  const char *zPattern,       /* The query pattern */
  unsigned int srchFlags      /* What to search over */
){
  Blob sql;
  if( srchFlags==0 ) return;
  sqlite3_create_function(g.db, "rank", 1, SQLITE_UTF8, 0,
     search_rank_sqlfunc, 0, 0);
  blob_init(&sql, 0, 0);
  blob_appendf(&sql,
    "INSERT INTO x(label,url,score,id,date,snip) "
    " SELECT ftsdocs.label,"
    "        ftsdocs.url,"
    "        rank(matchinfo(ftsidx,'pcsx')),"







|







920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
*/
static void search_indexed(
  const char *zPattern,       /* The query pattern */
  unsigned int srchFlags      /* What to search over */
){
  Blob sql;
  if( srchFlags==0 ) return;
  sqlite3_create_function(g.db, "rank", 1, SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
     search_rank_sqlfunc, 0, 0);
  blob_init(&sql, 0, 0);
  blob_appendf(&sql,
    "INSERT INTO x(label,url,score,id,date,snip) "
    " SELECT ftsdocs.label,"
    "        ftsdocs.url,"
    "        rank(matchinfo(ftsidx,'pcsx')),"
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
/*
** The document described by cType,rid,zName is about to be added or
** updated.  If the document has already been indexed, then unindex it
** now while we still have access to the old content.  Add the document
** to the queue of documents that need to be indexed or reindexed.
*/
void search_doc_touch(char cType, int rid, const char *zName){
  if( search_index_exists() ){
    char zType[2];
    zType[0] = cType;
    zType[1] = 0;
    search_sql_setup(g.db);
    db_multi_exec(
       "DELETE FROM ftsidx WHERE docid IN"
       "    (SELECT rowid FROM ftsdocs WHERE type=%Q AND rid=%d AND idxed)",







|







1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
/*
** The document described by cType,rid,zName is about to be added or
** updated.  If the document has already been indexed, then unindex it
** now while we still have access to the old content.  Add the document
** to the queue of documents that need to be indexed or reindexed.
*/
void search_doc_touch(char cType, int rid, const char *zName){
  if( search_index_exists() && !content_is_private(rid) ){
    char zType[2];
    zType[0] = cType;
    zType[1] = 0;
    search_sql_setup(g.db);
    db_multi_exec(
       "DELETE FROM ftsidx WHERE docid IN"
       "    (SELECT rowid FROM ftsdocs WHERE type=%Q AND rid=%d AND idxed)",
1833
1834
1835
1836
1837
1838
1839
1840



1841
1842
1843
1844
1845
1846
1847




1848
1849
1850
1851
1852
1853
1854
**     stemmer (on|off)   Turn the Porter stemmer on or off for indexed
**                        search.  (Unindexed search is never stemmed.)
**
** The current search settings are displayed after any changes are applied.
** Run this command with no arguments to simply see the settings.
*/
void fts_config_cmd(void){
  static const struct { int iCmd; const char *z; } aCmd[] = {



     { 1,  "reindex"  },
     { 2,  "index"    },
     { 3,  "disable"  },
     { 4,  "enable"   },
     { 5,  "stemmer"  },
  };
  static const struct { const char *zSetting; const char *zName; const char *zSw; } aSetng[] = {




     { "search-ci",       "check-in search:",  "c" },
     { "search-doc",      "document search:",  "d" },
     { "search-tkt",      "ticket search:",    "t" },
     { "search-wiki",     "wiki search:",      "w" },
     { "search-technote", "tech note search:", "e" },
     { "search-forum",    "forum search:",     "f" },
  };







|
>
>
>






|
>
>
>
>







1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
**     stemmer (on|off)   Turn the Porter stemmer on or off for indexed
**                        search.  (Unindexed search is never stemmed.)
**
** The current search settings are displayed after any changes are applied.
** Run this command with no arguments to simply see the settings.
*/
void fts_config_cmd(void){
  static const struct { 
    int iCmd;
    const char *z;
  } aCmd[] = {
     { 1,  "reindex"  },
     { 2,  "index"    },
     { 3,  "disable"  },
     { 4,  "enable"   },
     { 5,  "stemmer"  },
  };
  static const struct {
    const char *zSetting;
    const char *zName;
    const char *zSw;
  } aSetng[] = {
     { "search-ci",       "check-in search:",  "c" },
     { "search-doc",      "document search:",  "d" },
     { "search-tkt",      "ticket search:",    "t" },
     { "search-wiki",     "wiki search:",      "w" },
     { "search-technote", "tech note search:", "e" },
     { "search-forum",    "forum search:",     "f" },
  };
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948


1949
1950
1951

1952
1953
1954
1955
1956
1957



1958
1959
1960
1961
1962
1963
1964
1965
1966










1967




1968
1969
1970
1971
1972
1973
1974
1975
1976

1977
1978








1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995

1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006

2007
2008




2009


2010





2011


2012
2013

2014
2015

2016
2017
2018
2019
*/
void search_data_page(void){
  Stmt q;
  const char *zId = P("id");
  const char *zType = P("y");
  const char *zIdxed = P("ixed");
  int id;
  int cnt = 0;
  login_check_credentials();
  if( !g.perm.Admin ){ login_needed(0); return; }
  if( !search_index_exists() ){
    @ <p>Indexed search is disabled
    style_footer();
    return;
  }


  if( zId!=0 && (id = atoi(zId))>0 ){
    /* Show information about a single ftsdocs entry */
    style_header("Information about ftsdoc entry %d", id);

    db_prepare(&q,
      "SELECT type||rid, name, idxed, label, url, datetime(mtime)"
      "  FROM ftsdocs WHERE rowid=%d", id
    );
    if( db_step(&q)==SQLITE_ROW ){
      const char *zUrl = db_column_text(&q,4);



      @ <table border=0>
      @ <tr><td align='right'>rowid:<td>&nbsp;&nbsp;<td>%d(id)
      @ <tr><td align='right'>id:<td><td>%s(db_column_text(&q,0))
      @ <tr><td align='right'>name:<td><td>%h(db_column_text(&q,1))
      @ <tr><td align='right'>idxed:<td><td>%d(db_column_int(&q,2))
      @ <tr><td align='right'>label:<td><td>%h(db_column_text(&q,3))
      @ <tr><td align='right'>url:<td><td>
      @ <a href='%R%s(zUrl)'>%h(zUrl)</a>
      @ <tr><td align='right'>mtime:<td><td>%s(db_column_text(&q,5))










      @ </table>




    }
    db_finalize(&q);
    style_footer();
    return;
  }
  if( zType!=0 && zType[0]!=0 && zType[1]==0 &&
      zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0
  ){
    int ixed = zIdxed[0]=='1';

    style_header("List of '%c' documents that are%s indexed",
                 zType[0], ixed ? "" : " not");








    db_prepare(&q,
      "SELECT rowid, type||rid ||' '|| coalesce(label,'')"
      "  FROM ftsdocs WHERE type='%c' AND %s idxed",
      zType[0], ixed ? "" : "NOT"
    );
    @ <ul>
    while( db_step(&q)==SQLITE_ROW ){
      @ <li> <a href='test-ftsdocs?id=%d(db_column_int(&q,0))'>
      @ %h(db_column_text(&q,1))</a>
    }
    @ </ul>
    db_finalize(&q);
    style_footer();
    return;
  }
  style_header("Summary of ftsdocs");
  db_prepare(&q,

     "SELECT type, idxed, count(*) FROM ftsdocs"
     " GROUP BY 1, 2 ORDER BY 3 DESC"
  );
  @ <table border=1 cellpadding=3 cellspacing=0>
  @ <thead>
  @ <tr><th>Type<th>Indexed?<th>Count<th>Link
  @ </thead>
  @ <tbody>
  while( db_step(&q)==SQLITE_ROW ){
    const char *zType = db_column_text(&q,0);
    int idxed = db_column_int(&q,1);

    int n = db_column_int(&q,2);
    @ <tr><td>%h(zType)<td>%d(idxed)




    @ <td>%d(n)


    @ <td><a href='test-ftsdocs?y=%s(zType)&ixed=%d(idxed)'>listing</a>





    @ </tr>


    cnt += n;
  }

  @ </tbody><tfooter>
  @ <tr><th>Total<th><th>%d(cnt)<th>

  @ </tfooter>
  @ </table>
  style_footer();
}







|







>
>



>






>
>
>

|
|






>
>
>
>
>
>
>
>
>
>

>
>
>
>









>


>
>
>
>
>
>
>
>

















>
|
|



|




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

>
>
|

>

|
>




1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
*/
void search_data_page(void){
  Stmt q;
  const char *zId = P("id");
  const char *zType = P("y");
  const char *zIdxed = P("ixed");
  int id;
  int cnt1 = 0, cnt2 = 0, cnt3 = 0;
  login_check_credentials();
  if( !g.perm.Admin ){ login_needed(0); return; }
  if( !search_index_exists() ){
    @ <p>Indexed search is disabled
    style_footer();
    return;
  }
  search_sql_setup(g.db);
  style_submenu_element("Setup","%R/srchsetup");
  if( zId!=0 && (id = atoi(zId))>0 ){
    /* Show information about a single ftsdocs entry */
    style_header("Information about ftsdoc entry %d", id);
    style_submenu_element("Summary","%R/test-ftsdocs");
    db_prepare(&q,
      "SELECT type||rid, name, idxed, label, url, datetime(mtime)"
      "  FROM ftsdocs WHERE rowid=%d", id
    );
    if( db_step(&q)==SQLITE_ROW ){
      const char *zUrl = db_column_text(&q,4);
      const char *zDocId = db_column_text(&q,0);
      char *zName;
      char *z;
      @ <table border=0>
      @ <tr><td align='right'>docid:<td>&nbsp;&nbsp;<td>%d(id)
      @ <tr><td align='right'>id:<td><td>%s(zDocId)
      @ <tr><td align='right'>name:<td><td>%h(db_column_text(&q,1))
      @ <tr><td align='right'>idxed:<td><td>%d(db_column_int(&q,2))
      @ <tr><td align='right'>label:<td><td>%h(db_column_text(&q,3))
      @ <tr><td align='right'>url:<td><td>
      @ <a href='%R%s(zUrl)'>%h(zUrl)</a>
      @ <tr><td align='right'>mtime:<td><td>%s(db_column_text(&q,5))
      z = db_text(0, "SELECT title FROM ftsidx WHERE docid=%d",id);
      if( z && z[0] ){
        @ <tr><td align="right">title:<td><td>%h(z)
        fossil_free(z);
      }
      z = db_text(0, "SELECT body FROM ftsidx WHERE docid=%d",id);
      if( z && z[0] ){
        @ <tr><td align="right" valign="top">body:<td><td>%h(z)
        fossil_free(z);
      }
      @ </table>
      zName = mprintf("Indexed '%c' docs",zDocId[0]);
      style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zDocId[0]);
      zName = mprintf("Unindexed '%c' docs",zDocId[0]);
      style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zDocId[0]);
    }
    db_finalize(&q);
    style_footer();
    return;
  }
  if( zType!=0 && zType[0]!=0 && zType[1]==0 &&
      zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0
  ){
    int ixed = zIdxed[0]=='1';
    char *zName;
    style_header("List of '%c' documents that are%s indexed",
                 zType[0], ixed ? "" : " not");
    style_submenu_element("Summary","%R/test-ftsdocs");
    if( ixed==0 ){
      zName = mprintf("Indexed '%c' docs",zType[0]);
      style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zType[0]);
    }else{
      zName = mprintf("Unindexed '%c' docs",zType[0]);
      style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zType[0]);
    }
    db_prepare(&q,
      "SELECT rowid, type||rid ||' '|| coalesce(label,'')"
      "  FROM ftsdocs WHERE type='%c' AND %s idxed",
      zType[0], ixed ? "" : "NOT"
    );
    @ <ul>
    while( db_step(&q)==SQLITE_ROW ){
      @ <li> <a href='test-ftsdocs?id=%d(db_column_int(&q,0))'>
      @ %h(db_column_text(&q,1))</a>
    }
    @ </ul>
    db_finalize(&q);
    style_footer();
    return;
  }
  style_header("Summary of ftsdocs");
  db_prepare(&q,
     "SELECT type, sum(idxed IS TRUE), sum(idxed IS FALSE), count(*)"
     "  FROM ftsdocs"
     " GROUP BY 1 ORDER BY 4 DESC"
  );
  @ <table border=1 cellpadding=3 cellspacing=0>
  @ <thead>
  @ <tr><th>Type<th>Indexed<th>Unindexed<th>Total
  @ </thead>
  @ <tbody>
  while( db_step(&q)==SQLITE_ROW ){
    const char *zType = db_column_text(&q,0);
    int nIndexed = db_column_int(&q, 1);
    int nUnindexed = db_column_int(&q, 2);
    int nTotal = db_column_int(&q, 3);
    @ <tr><td>%h(zType)
    if( nIndexed>0 ){
      @ <td align="right"><a href='%R/test-ftsdocs?y=%s(zType)&ixed=1'>\
      @ %d(nIndexed)</a>
    }else{
      @ <td align="right">0
    }
    if( nUnindexed>0 ){
      @ <td align="right"><a href='%R/test-ftsdocs?y=%s(zType)&ixed=0'>\
      @ %d(nUnindexed)</a>
    }else{
      @ <td align="right">0
    }
    @ <td align="right">%d(nTotal)
    @ </tr>
    cnt1 += nIndexed;
    cnt2 += nUnindexed;
    cnt3 += nTotal;
  }
  db_finalize(&q);
  @ </tbody><tfooter>
  @ <tr><th>Total<th align="right">%d(cnt1)<th align="right">%d(cnt2)
  @ <th align="right">%d(cnt3)
  @ </tfooter>
  @ </table>
  style_footer();
}
Changes to src/security_audit.c.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109


110
111

112
113

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
    if( strchr(zCap, zTest[0]) ) return 1;
    zTest++;
  }
  return 0;
}

/*
** Extract the content-security-policy from the reply header.  Parse it
** up into separate fields, and return a pointer to a null-terminated
** array of pointers to strings, one entry for each field.  Or return
** a NULL pointer if no CSP could be located in the header.
**
** Memory to hold the returned array and of the strings is obtained from
** a single memory allocation, which the caller should free to avoid a
** memory leak.
*/
static char **parse_content_security_policy(void){
  char **azCSP = 0;
  int nCSP = 0;
  const char *zHeader;
  const char *zAll;
  char *zCopy;
  int nAll = 0;
  int ii, jj, n, nx = 0;
  int nSemi;

  zHeader = cgi_header();
  if( zHeader==0 ) return 0;
  for(ii=0; zHeader[ii]; ii+=n){
    n = html_token_length(zHeader+ii);
    if( zHeader[ii]=='<'
     && fossil_strnicmp(html_attribute(zHeader+ii,"http-equiv",&nx),
                        "Content-Security-Policy",23)==0
     && nx==23
     && (zAll = html_attribute(zHeader+ii,"content",&nAll))!=0
    ){
      for(jj=nSemi=0; jj<nAll; jj++){ if( zAll[jj]==';' ) nSemi++; }
      azCSP = fossil_malloc( nAll+1 + (nSemi+2)*sizeof(char*) );
      zCopy = (char*)&azCSP[nSemi+2];
      memcpy(zCopy,zAll,nAll);
      zCopy[nAll] = 0;
      while( fossil_isspace(zCopy[0]) || zCopy[0]==';' ){ zCopy++; }
      azCSP[0] = zCopy;
      nCSP = 1;
      for(jj=0; zCopy[jj]; jj++){
        if( zCopy[jj]==';' ){
          int k;
          for(k=jj-1; k>0 && fossil_isspace(zCopy[k]); k--){ zCopy[k] = 0; }
          zCopy[jj] = 0;
          while( jj+1<nAll
             && (fossil_isspace(zCopy[jj+1]) || zCopy[jj+1]==';')
          ){
            jj++;
          }
          assert( nCSP<nSemi+1 );
          azCSP[nCSP++] = zCopy+jj;
        }
      }
      assert( nCSP<=nSemi+2 );
      azCSP[nCSP] = 0;

      return azCSP;
    }
  }
  return 0;
}

/*
** WEBPAGE: secaudit0
**
** Run a security audit of the current Fossil setup, looking
** for configuration problems that might allow unauthorized
** access to the repository.
**
** This page requires administrator access.  It is usually
** accessed using the Admin/Security-Audit menu option
** from any of the default skins.
*/
void secaudit0_page(void){
  const char *zAnonCap;      /* Capabilities of user "anonymous" and "nobody" */


  const char *zPubPages;     /* GLOB pattern for public pages */
  const char *zSelfCap;      /* Capabilities of self-registered users */

  char *z;
  int n;

  char **azCSP;              /* Parsed content security policy */

  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  style_header("Security Audit");
  @ <ol>

  /* Step 1:  Determine if the repository is public or private.  "Public"
  ** means that any anonymous user on the internet can access all content.
  ** "Private" repos require (non-anonymous) login to access all content,
  ** though some content may be accessible anonymously.
  */
  zAnonCap = db_text("", "SELECT fullcap(NULL)");


  zPubPages = db_get("public-pages",0);
  if( db_get_boolean("self-register",0) ){
    CapabilityString *pCap;
    pCap = capability_add(0, db_get("default-perms",0));
    capability_expand(pCap);
    zSelfCap = capability_string(pCap);
    capability_free(pCap);
  }else{
    zSelfCap = fossil_strdup("");
  }
  if( hasAnyCap(zAnonCap,"as") ){
    @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
    @ it grants administrator privileges to anonymous users.  You
    @ should <a href="takeitprivate">take this repository private</a>
    @ immediately!  Or, at least remove the Setup and Admin privileges
    @ for users "anonymous" and "login" on the
    @ <a href="setup_ulist">User Configuration</a> page.
  }else if( hasAnyCap(zSelfCap,"as") ){
    @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
    @ it grants administrator privileges to self-registered users.  You
    @ should <a href="takeitprivate">take this repository private</a>
    @ and/or disable self-registration
    @ immediately!  Or, at least remove the Setup and Admin privileges
    @ from the default permissions for new users.
  }else if( hasAnyCap(zAnonCap,"y") ){







|
|










<
|


|


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















>
>


>


>
















>
>

|
<
|
|
|
|
<
<
<







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

50
51
52
53
54
55
56







57

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

127
128
129
130



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
    if( strchr(zCap, zTest[0]) ) return 1;
    zTest++;
  }
  return 0;
}

/*
** Parse the content-security-policy
** into separate fields, and return a pointer to a null-terminated
** array of pointers to strings, one entry for each field.  Or return
** a NULL pointer if no CSP could be located in the header.
**
** Memory to hold the returned array and of the strings is obtained from
** a single memory allocation, which the caller should free to avoid a
** memory leak.
*/
static char **parse_content_security_policy(void){
  char **azCSP = 0;
  int nCSP = 0;

  char *zAll;
  char *zCopy;
  int nAll = 0;
  int jj;
  int nSemi;

  zAll = style_csp(0);







  nAll = (int)strlen(zAll);

  for(jj=nSemi=0; jj<nAll; jj++){ if( zAll[jj]==';' ) nSemi++; }
  azCSP = fossil_malloc( nAll+1+(nSemi+2)*sizeof(char*) );
  zCopy = (char*)&azCSP[nSemi+2];
  memcpy(zCopy,zAll,nAll);
  zCopy[nAll] = 0;
  while( fossil_isspace(zCopy[0]) || zCopy[0]==';' ){ zCopy++; }
  azCSP[0] = zCopy;
  nCSP = 1;
  for(jj=0; zCopy[jj]; jj++){
    if( zCopy[jj]==';' ){
      int k;
      for(k=jj-1; k>0 && fossil_isspace(zCopy[k]); k--){ zCopy[k] = 0; }
      zCopy[jj] = 0;
      while( jj+1<nAll
         && (fossil_isspace(zCopy[jj+1]) || zCopy[jj+1]==';')
      ){
        jj++;
      }
      assert( nCSP<nSemi+1 );
      azCSP[nCSP++] = zCopy+jj;
    }
  }
  assert( nCSP<=nSemi+2 );
  azCSP[nCSP] = 0;
  fossil_free(zAll);
  return azCSP;



}

/*
** WEBPAGE: secaudit0
**
** Run a security audit of the current Fossil setup, looking
** for configuration problems that might allow unauthorized
** access to the repository.
**
** This page requires administrator access.  It is usually
** accessed using the Admin/Security-Audit menu option
** from any of the default skins.
*/
void secaudit0_page(void){
  const char *zAnonCap;      /* Capabilities of user "anonymous" and "nobody" */
  const char *zDevCap;       /* Capabilities of user group "developer" */
  const char *zReadCap;      /* Capabilities of user group "reader" */
  const char *zPubPages;     /* GLOB pattern for public pages */
  const char *zSelfCap;      /* Capabilities of self-registered users */
  int hasSelfReg = 0;        /* True if able to self-register */
  char *z;
  int n;
  CapabilityString *pCap;
  char **azCSP;              /* Parsed content security policy */

  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  style_header("Security Audit");
  @ <ol>

  /* Step 1:  Determine if the repository is public or private.  "Public"
  ** means that any anonymous user on the internet can access all content.
  ** "Private" repos require (non-anonymous) login to access all content,
  ** though some content may be accessible anonymously.
  */
  zAnonCap = db_text("", "SELECT fullcap(NULL)");
  zDevCap  = db_text("", "SELECT fullcap('v')");
  zReadCap = db_text("", "SELECT fullcap('u')");
  zPubPages = db_get("public-pages",0);
  hasSelfReg = db_get_boolean("self-register",0);

  pCap = capability_add(0, db_get("default-perms","u"));
  capability_expand(pCap);
  zSelfCap = capability_string(pCap);
  capability_free(pCap);



  if( hasAnyCap(zAnonCap,"as") ){
    @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
    @ it grants administrator privileges to anonymous users.  You
    @ should <a href="takeitprivate">take this repository private</a>
    @ immediately!  Or, at least remove the Setup and Admin privileges
    @ for users "anonymous" and "login" on the
    @ <a href="setup_ulist">User Configuration</a> page.
  }else if( hasAnyCap(zSelfCap,"as") && hasSelfReg ){
    @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
    @ it grants administrator privileges to self-registered users.  You
    @ should <a href="takeitprivate">take this repository private</a>
    @ and/or disable self-registration
    @ immediately!  Or, at least remove the Setup and Admin privileges
    @ from the default permissions for new users.
  }else if( hasAnyCap(zAnonCap,"y") ){
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192

193
194
195
196
197
198
199
200
201
202



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222





























223
224
225
226
227
228
229
    @ <p>Fix this by <a href="takeitprivate">taking the repository private</a>
    @ or by removing the "y" permission from the default permissions or
    @ by disabling self-registration.
  }else if( hasAnyCap(zAnonCap,"goz") ){
    @ <li><p>This repository is <big><b>PUBLIC</b></big>. All
    @ checked-in content can be accessed by anonymous users.
    @ <a href="takeitprivate">Take it private</a>.<p>
  }else if( hasAnyCap(zSelfCap,"goz") ){
    @ <li><p>This repository is <big><b>PUBLIC</b></big> because all
    @ checked-in content can be accessed by self-registered users.
    @ This repostory would be private if you disabled self-registration.</p>
  }else if( !hasAnyCap(zAnonCap, "jrwy234567")
         && !hasAnyCap(zSelfCap, "jrwy234567")
         && (zPubPages==0 || zPubPages[0]==0) ){
    @ <li><p>This repository is <big><b>Completely PRIVATE</b></big>.
    @ A valid login and password is required to access any content.
  }else{
    @ <li><p>This repository is <big><b>Mostly PRIVATE</b></big>.
    @ A valid login and password is usually required, however some
    @ content can be accessed either anonymously or by self-registered
    @ users:
    @ <ul>

    if( hasAnyCap(zAnonCap,"j") || hasAnyCap(zSelfCap,"j") ){
      @ <li> Wiki pages
    }
    if( hasAnyCap(zAnonCap,"r") || hasAnyCap(zSelfCap,"r") ){
      @ <li> Tickets
    }
    if( hasAnyCap(zAnonCap,"234567") || hasAnyCap(zSelfCap,"234567") ){
      @ <li> Forum posts

    }
    if( zPubPages && zPubPages[0] ){
      Glob *pGlob = glob_create(zPubPages);
      int i;
      @ <li> URLs that match any of these GLOB patterns:
      @ <ul>
      for(i=0; i<pGlob->nPattern; i++){
        @ <li> %h(pGlob->azPattern[i])
      }
      @ </ul>



    }
    @ </ul>
    if( zPubPages && zPubPages[0] ){
      @ <p>Change GLOB patterns exceptions using the "Public pages" setting
      @ on the <a href="setup_access">Access Settings</a> page.</p>
    }
  }

  /* Make sure the HTTPS is required for login, at least, so that the
  ** password does not go across the Internet in the clear.
  */
  if( db_get_int("redirect-to-https",0)==0 ){
    @ <li><p><b>WARNING:</b>
    @ Sensitive material such as login passwords can be sent over an
    @ unencrypted connection.
    @ <p>Fix this by changing the "Redirect to HTTPS" setting on the
    @ <a href="setup_access">Access Control</a> page. If you were using
    @ the old "Redirect to HTTPS on Login Page" setting, switch to the
    @ new setting: it has a more secure implementation.
  }






























  /* Anonymous users should not be able to harvest email addresses
  ** from tickets.
  */
  if( hasAnyCap(zAnonCap, "e") ){
    @ <li><p><b>WARNING:</b>
    @ Anonymous users can view email addresses and other personally







|




|









>
|
|
|
|
|
|
|
|
>




|
|




>
>
>




















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







154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
    @ <p>Fix this by <a href="takeitprivate">taking the repository private</a>
    @ or by removing the "y" permission from the default permissions or
    @ by disabling self-registration.
  }else if( hasAnyCap(zAnonCap,"goz") ){
    @ <li><p>This repository is <big><b>PUBLIC</b></big>. All
    @ checked-in content can be accessed by anonymous users.
    @ <a href="takeitprivate">Take it private</a>.<p>
  }else if( hasAnyCap(zSelfCap,"goz") && hasSelfReg ){
    @ <li><p>This repository is <big><b>PUBLIC</b></big> because all
    @ checked-in content can be accessed by self-registered users.
    @ This repostory would be private if you disabled self-registration.</p>
  }else if( !hasAnyCap(zAnonCap, "jrwy234567")
         && (!hasSelfReg || !hasAnyCap(zSelfCap, "jrwy234567"))
         && (zPubPages==0 || zPubPages[0]==0) ){
    @ <li><p>This repository is <big><b>Completely PRIVATE</b></big>.
    @ A valid login and password is required to access any content.
  }else{
    @ <li><p>This repository is <big><b>Mostly PRIVATE</b></big>.
    @ A valid login and password is usually required, however some
    @ content can be accessed either anonymously or by self-registered
    @ users:
    @ <ul>
    if( hasSelfReg ){
      if( hasAnyCap(zAnonCap,"j") || hasAnyCap(zSelfCap,"j") ){
        @ <li> Wiki pages
      }
      if( hasAnyCap(zAnonCap,"r") || hasAnyCap(zSelfCap,"r") ){
        @ <li> Tickets
      }
      if( hasAnyCap(zAnonCap,"234567") || hasAnyCap(zSelfCap,"234567") ){
        @ <li> Forum posts
      }
    }
    if( zPubPages && zPubPages[0] ){
      Glob *pGlob = glob_create(zPubPages);
      int i;
      @ <li> "Public Pages" are URLs that match any of these GLOB patterns:
      @ <p><ul>
      for(i=0; i<pGlob->nPattern; i++){
        @ <li> %h(pGlob->azPattern[i])
      }
      @ </ul>
      @ <p>Anoymous users are vested with capabilities "%h(zSelfCap)" on
      @ public pages. See the "Public Pages" entry in the
      @ "User capability summary" below.
    }
    @ </ul>
    if( zPubPages && zPubPages[0] ){
      @ <p>Change GLOB patterns exceptions using the "Public pages" setting
      @ on the <a href="setup_access">Access Settings</a> page.</p>
    }
  }

  /* Make sure the HTTPS is required for login, at least, so that the
  ** password does not go across the Internet in the clear.
  */
  if( db_get_int("redirect-to-https",0)==0 ){
    @ <li><p><b>WARNING:</b>
    @ Sensitive material such as login passwords can be sent over an
    @ unencrypted connection.
    @ <p>Fix this by changing the "Redirect to HTTPS" setting on the
    @ <a href="setup_access">Access Control</a> page. If you were using
    @ the old "Redirect to HTTPS on Login Page" setting, switch to the
    @ new setting: it has a more secure implementation.
  }

#ifdef FOSSIL_ENABLE_TH1_DOCS
  /* The use of embedded TH1 is dangerous.  Warn if it is possible.
  */
  if( !Th_AreDocsEnabled() ){
    @ <li><p>
    @ This server is compiled with -DFOSSIL_ENABLE_TH1_DOCS. TH1 docs
    @ are disabled for this particular repository, so you are safe for
    @ now.  However, to prevent future problems caused by accidentally
    @ enabling TH1 docs in the future, it is recommended that you
    @ recompile Fossil without the -DFOSSIL_ENABLE_TH1_DOCS flag.</p>
  }else{
    @ <li><p><b>DANGER:</b>
    @ This server is compiled with -DFOSSIL_ENABLE_TH1_DOCS and TH1 docs
    @ are enabled for this repository.  Anyone who can check-in or push
    @ to this repository can create a malicious TH1 script and then cause
    @ that script to be run on the server. This is a serious security concern.
    @ TH1 docs should only be enabled for repositories with a very limited
    @ number of trusted committers, and the repository should be monitored
    @ closely to ensure no hostile content sneaks in.  If a bad TH1 script
    @ does make it into the repository, the only want to prevent it from
    @ being run is to shun it.</p>
    @
    @ <p>Disable TH1 docs by recompiling Fossil without the
    @ -DFOSSIL_ENABLE_TH1_DOCS flag, and/or clear the th1-docs setting
    @ and ensure that the TH1_ENABLE_DOCS environment variable does not
    @ exist in the environment.</p>
  }
#endif

  /* Anonymous users should not be able to harvest email addresses
  ** from tickets.
  */
  if( hasAnyCap(zAnonCap, "e") ){
    @ <li><p><b>WARNING:</b>
    @ Anonymous users can view email addresses and other personally
255
256
257
258
259
260
261
262
263
264
265


266
267

268
269
270

271
272
273
274
275
276
277
    @ forum posts. This defeats the whole purpose of moderation.
    @ <p>Fix this by removing the "Mod-Wiki", "Mod-Tkt", and "Mod-Forum"
    @ privileges (<a href="%R/setup_ucap_list">capabilities</a> "fq5")
    @ from users "anonymous" and "nobody"
    @ on the <a href="setup_ulist">User Configuration</a> page.
  }

  /* Anonymous users probably should not be allowed to delete
  ** wiki or tickets.
  */
  if( hasAnyCap(zAnonCap, "d") ){


    @ <li><p><b>WARNING:</b>
    @ Anonymous users can delete wiki and tickets.

    @ <p>Fix this by removing the "Delete"
    @ privilege from users "anonymous" and "nobody" on the
    @ <a href="setup_ulist">User Configuration</a> page.

  }

  /* If anonymous users are allowed to create new Wiki, then
  ** wiki moderation should be activated to pervent spam.
  */
  if( hasAnyCap(zAnonCap, "fk") ){
    if( db_get_boolean("modreq-wiki",0)==0 ){







<
|
<
|
>
>

|
>
|
<
|
>







280
281
282
283
284
285
286

287

288
289
290
291
292
293
294

295
296
297
298
299
300
301
302
303
    @ forum posts. This defeats the whole purpose of moderation.
    @ <p>Fix this by removing the "Mod-Wiki", "Mod-Tkt", and "Mod-Forum"
    @ privileges (<a href="%R/setup_ucap_list">capabilities</a> "fq5")
    @ from users "anonymous" and "nobody"
    @ on the <a href="setup_ulist">User Configuration</a> page.
  }


  /* Obsolete:  */

  if( hasAnyCap(zAnonCap, "d") ||
      hasAnyCap(zDevCap,  "d") ||
      hasAnyCap(zReadCap, "d") ){
    @ <li><p><b>WARNING:</b>
    @ One or more users has the <a
    @ href="https://fossil-scm.org/forum/forumpost/43c78f4bef">obsolete</a>
    @ "d" capability. You should remove it using the

    @ <a href="setup_ulist">User Configuration</a> page in case we
    @ ever reuse the letter for another purpose.
  }

  /* If anonymous users are allowed to create new Wiki, then
  ** wiki moderation should be activated to pervent spam.
  */
  if( hasAnyCap(zAnonCap, "fk") ){
    if( db_get_boolean("modreq-wiki",0)==0 ){
525
526
527
528
529
530
531















532
533
534
535
536
537
538
    @ <li><p> Email alert configuration summary:
    @ <table class="label-value">
    stats_for_email();
    @ </table>
  }else{
    @ <li><p> Email alerts are disabled
  }
















  @ </ol>
  style_footer();
}

/*
** WEBPAGE: takeitprivate







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







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
    @ <li><p> Email alert configuration summary:
    @ <table class="label-value">
    stats_for_email();
    @ </table>
  }else{
    @ <li><p> Email alerts are disabled
  }

  n = db_int(0,"SELECT count(*) FROM ("
               "SELECT rid FROM phantom EXCEPT SELECT rid FROM private)");
  if( n>0 ){
    @ <li><p>\
    @ There exists public phantom artifacts in this repository, shown below.
    @ Phantom artifacts are artifacts whose hash name is referenced by some
    @ other artifact but whose content is unknown.  Some phantoms are marked
    @ private and those are ignored.  But public phantoms cause unnecessary
    @ sync traffic and might represent malicious attempts to corrupt the
    @ repository structure.
    @ </p>
    table_of_public_phantoms();
    @ </li>
  }

  @ </ol>
  style_footer();
}

/*
** WEBPAGE: takeitprivate
Changes to src/setup.c.
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
  onoff_attribute("Enable /test_env",
     "test_env_enable", "test_env_enable", 0, 0);
  @ <p>When enabled, the %h(g.zBaseURL)/test_env URL is available to all
  @ users.  When disabled (the default) only users Admin and Setup can visit
  @ the /test_env page.
  @ (Property: "test_env_enable")
  @ </p>









  @
  @ <hr />
  onoff_attribute("Allow REMOTE_USER authentication",
     "remote_user_ok", "remote_user_ok", 0, 0);
  @ <p>When enabled, if the REMOTE_USER environment variable is set to the
  @ login name of a valid user and no other login credentials are available,
  @ then the REMOTE_USER is accepted as an authenticated user.
  @ (Property: "remote_user_ok")
  @ </p>
  @
  @ <hr />
  onoff_attribute("Allow HTTP_AUTHENTICATION authentication",
     "http_authentication_ok", "http_authentication_ok", 0, 0);
  @ <p>When enabled, allow the use of the HTTP_AUTHENTICATION environment
  @ variable or the "Authentication:" HTTP header to find the username and
  @ password. This is another way of supporting Basic Authenitication.
  @ (Property: "http_authentication_ok")
  @ </p>
  @
  @ <hr />
  entry_attribute("IP address terms used in login cookie", 3,
                  "ip-prefix-terms", "ipt", "2", 0);
  @ <p>The number of octets of of the IP address used in the login cookie.
  @ Set to zero to omit the IP address from the login cookie.  A value of
  @ 2 is recommended.
  @ (Property: "ip-prefix-terms")
  @ </p>
  @
  @ <hr />
  entry_attribute("Login expiration time", 6, "cookie-expire", "cex",
                  "8766", 0);
  @ <p>The number of hours for which a login is valid.  This must be a
  @ positive number.  The default is 8766 hours which is approximately equal
  @ to a year.
  @ (Property: "cookie-expire")</p>







>
>
>
>
>
>
>
>
>



















<
<
<
<
<
<
<
<
<







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
  onoff_attribute("Enable /test_env",
     "test_env_enable", "test_env_enable", 0, 0);
  @ <p>When enabled, the %h(g.zBaseURL)/test_env URL is available to all
  @ users.  When disabled (the default) only users Admin and Setup can visit
  @ the /test_env page.
  @ (Property: "test_env_enable")
  @ </p>
  @
  @ <hr />
  onoff_attribute("Enable /artifact_stats",
     "artifact_stats_enable", "artifact_stats_enable", 0, 0);
  @ <p>When enabled, the %h(g.zBaseURL)/artifact_stats URL is available to all
  @ users.  When disabled (the default) only users with check-in privilege may
  @ access the /artifact_stats page.
  @ (Property: "artifact_stats_enable")
  @ </p>
  @
  @ <hr />
  onoff_attribute("Allow REMOTE_USER authentication",
     "remote_user_ok", "remote_user_ok", 0, 0);
  @ <p>When enabled, if the REMOTE_USER environment variable is set to the
  @ login name of a valid user and no other login credentials are available,
  @ then the REMOTE_USER is accepted as an authenticated user.
  @ (Property: "remote_user_ok")
  @ </p>
  @
  @ <hr />
  onoff_attribute("Allow HTTP_AUTHENTICATION authentication",
     "http_authentication_ok", "http_authentication_ok", 0, 0);
  @ <p>When enabled, allow the use of the HTTP_AUTHENTICATION environment
  @ variable or the "Authentication:" HTTP header to find the username and
  @ password. This is another way of supporting Basic Authenitication.
  @ (Property: "http_authentication_ok")
  @ </p>
  @









  @ <hr />
  entry_attribute("Login expiration time", 6, "cookie-expire", "cex",
                  "8766", 0);
  @ <p>The number of hours for which a login is valid.  This must be a
  @ positive number.  The default is 8766 hours which is approximately equal
  @ to a year.
  @ (Property: "cookie-expire")</p>
486
487
488
489
490
491
492
493



494
495
496
497
498
499
500
501
502
503
504



505









506







507








508
509
510
511
512
513
514
515
  @ for users who are not logged in. (Property: "require-captcha")</p>

  @ <hr />
  entry_attribute("Public pages", 30, "public-pages",
                  "pubpage", "", 0);
  @ <p>A comma-separated list of glob patterns for pages that are accessible
  @ without needing a login and using the privileges given by the
  @ "Default privileges" setting below.  Example use case: Set this field



  @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the
  @ latest version of the embedded documentation in the www/ folder without
  @ allowing them to see the rest of the source code.
  @ (Property: "public-pages")
  @ </p>

  @ <hr />
  onoff_attribute("Allow users to register themselves",
                  "self-register", "selfregister", 0, 0);
  @ <p>Allow users to register themselves through the HTTP UI.
  @ The registration form always requires filling in a CAPTCHA



  @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone









  @ can register under any user name. This option is useful for public projects







  @ where you do not want everyone in any ticket discussion to be named








  @ "Anonymous".  (Property: "self-register")</p>

  @ <hr />
  entry_attribute("Default privileges", 10, "default-perms",
                  "defaultperms", "u", 0);
  @ <p>Permissions given to users that... <ul><li>register themselves using
  @ the self-registration procedure (if enabled), or <li>access "public"
  @ pages identified by the public-pages glob pattern above, or <li>







|
>
>
>
|







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







486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  @ for users who are not logged in. (Property: "require-captcha")</p>

  @ <hr />
  entry_attribute("Public pages", 30, "public-pages",
                  "pubpage", "", 0);
  @ <p>A comma-separated list of glob patterns for pages that are accessible
  @ without needing a login and using the privileges given by the
  @ "Default privileges" setting below. 
  @
  @ <p>Example use case: Set this field to "/doc/trunk/www/*" and set
  @ the "Default privileges" to include the "o" privilege
  @ to give anonymous users read-only permission to the
  @ latest version of the embedded documentation in the www/ folder without
  @ allowing them to see the rest of the source code.
  @ (Property: "public-pages")
  @ </p>

  @ <hr />
  onoff_attribute("Allow users to register themselves",
                  "self-register", "selfreg", 0, 0);
  @ <p>Allow users to register themselves on the /register webpage.
  @ A self-registration creates a new entry in the USER table and
  @ perhaps also in the SUBSCRIBER table if email notification is
  @ enabled.
  @ (Property: "self-register")</p>

  @ <hr />
  onoff_attribute("Email verification required for self-registration",
                  "selfreg-verify", "sfverify", 0, 0);
  @ <p>If enabled, self-registration creates a new entry in the USER table
  @ with only capabilities "7".  The default user capabilities are not
  @ added until the email address associated with the self-registration
  @ has been verified. This setting only makes sense if
  @ email notifications are enabled.
  @ (Property: "selfreg-verify")</p>

  @ <hr />
  onoff_attribute("Allow anonymous subscriptions",
                  "anon-subscribe", "anonsub", 1, 0);
  @ <p>If disabled, email notification subscriptions are only allowed
  @ for users with a login.  If Nobody or Anonymous visit the /subscribe
  @ page, they are redirected to /register or /login.
  @ (Property: "anon-subscribe")</p>

  @ <hr />
  entry_attribute("Authorized subscription email addresses", 35,
                  "auth-sub-email", "asemail", "", 0);
  @ <p>This is a comma-separated list of GLOB patterns that specify
  @ email addresses that are authorized to subscriptions.  If blank
  @ (the usual case), then any email address can be used to self-register.
  @ This setting is used to limit subscriptions to members of a particular
  @ organization or group based on their email address.
  @ (Property: "auth-sub-email")</p>

  @ <hr />
  entry_attribute("Default privileges", 10, "default-perms",
                  "defaultperms", "u", 0);
  @ <p>Permissions given to users that... <ul><li>register themselves using
  @ the self-registration procedure (if enabled), or <li>access "public"
  @ pages identified by the public-pages glob pattern above, or <li>
731
732
733
734
735
736
737







738
739
740
741
742
743
744
  }else if( tmDiff<0.0 ){
    sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", -tmDiff);
    @ %s(zTmDiff) hours behind UTC.</p>
  }else{
    @ %s(zTmDiff) hours ahead of UTC.</p>
  }
  @ <p>(Property: "timeline-utc")







  @ <hr />
  multiple_choice_attribute("Per-Item Time Format", "timeline-date-format",
            "tdf", "0", count(azTimeFormats)/2, azTimeFormats);
  @ <p>If the "HH:MM" or "HH:MM:SS" format is selected, then the date is shown
  @ in a separate box (using CSS class "timelineDate") whenever the date
  @ changes.  With the "YYYY-MM-DD&nbsp;HH:MM" and "YYMMDD ..." formats,
  @ the complete date and time is shown on every timeline entry using the







>
>
>
>
>
>
>







761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
  }else if( tmDiff<0.0 ){
    sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", -tmDiff);
    @ %s(zTmDiff) hours behind UTC.</p>
  }else{
    @ %s(zTmDiff) hours ahead of UTC.</p>
  }
  @ <p>(Property: "timeline-utc")

  @ <hr />
  multiple_choice_attribute("Style", "timeline-default-style",
            "tdss", "0", N_TIMELINE_VIEW_STYLE, timeline_view_styles);
  @ <p>The default timeline viewing style, for when the user has not
  @ specified an alternative.  (Property: "timeline-default-style")</p>

  @ <hr />
  multiple_choice_attribute("Per-Item Time Format", "timeline-date-format",
            "tdf", "0", count(azTimeFormats)/2, azTimeFormats);
  @ <p>If the "HH:MM" or "HH:MM:SS" format is selected, then the date is shown
  @ in a separate box (using CSS class "timelineDate") whenever the date
  @ changes.  With the "YYYY-MM-DD&nbsp;HH:MM" and "YYMMDD ..." formats,
  @ the complete date and time is shown on every timeline entry using the
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
        @ <br />
      }
    }
  }
  @ <br /><input type="submit"  name="submit" value="Apply Changes" />
  @ </td><td style="width:50px;"></td><td valign="top">
  for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
    if( pSet->width!=0 && !pSet->forceTextArea ){
      int hasVersionableValue = pSet->versionable &&
          (db_get_versioned(pSet->name, NULL)!=0);
      entry_attribute("", /*pSet->width*/ 25, pSet->name,
                      pSet->var!=0 ? pSet->var : pSet->name,
                      (char*)pSet->def, hasVersionableValue);
      @ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a>
      if( pSet->versionable ){
        @  (v)<br />
      } else {
        @ <br />
      }
    }
  }
  @ </td><td style="width:50px;"></td><td valign="top">
  for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
    if( pSet->width!=0 && pSet->forceTextArea ){
      int hasVersionableValue = db_get_versioned(pSet->name, NULL)!=0;
      @ <a href='%R/help?cmd=%s(pSet->name)'>%s(pSet->name)</a>
      if( pSet->versionable ){
        @  (v)<br />
      } else {
        @ <br />
      }







|















|







875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
        @ <br />
      }
    }
  }
  @ <br /><input type="submit"  name="submit" value="Apply Changes" />
  @ </td><td style="width:50px;"></td><td valign="top">
  for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
    if( pSet->width>0 && !pSet->forceTextArea ){
      int hasVersionableValue = pSet->versionable &&
          (db_get_versioned(pSet->name, NULL)!=0);
      entry_attribute("", /*pSet->width*/ 25, pSet->name,
                      pSet->var!=0 ? pSet->var : pSet->name,
                      (char*)pSet->def, hasVersionableValue);
      @ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a>
      if( pSet->versionable ){
        @  (v)<br />
      } else {
        @ <br />
      }
    }
  }
  @ </td><td style="width:50px;"></td><td valign="top">
  for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
    if( pSet->width>0 && pSet->forceTextArea ){
      int hasVersionableValue = db_get_versioned(pSet->name, NULL)!=0;
      @ <a href='%R/help?cmd=%s(pSet->name)'>%s(pSet->name)</a>
      if( pSet->versionable ){
        @  (v)<br />
      } else {
        @ <br />
      }
1628
1629
1630
1631
1632
1633
1634

1635
1636
1637
1638
1639
1640
1641
  }
  if( search_index_exists() ){
    @ <p>Currently using an SQLite FTS4 search index. This makes search
    @ run faster, especially on large repositories, but takes up space.</p>
    onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0);
    @ <p><input type="submit" name="fts0" value="Delete The Full-Text Index">
    @ <input type="submit" name="fts1" value="Rebuild The Full-Text Index">

  }else{
    @ <p>The SQLite FTS4 search index is disabled.  All searching will be
    @ a full-text scan.  This usually works fine, but can be slow for
    @ larger repositories.</p>
    onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0);
    @ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
  }







>







1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
  }
  if( search_index_exists() ){
    @ <p>Currently using an SQLite FTS4 search index. This makes search
    @ run faster, especially on large repositories, but takes up space.</p>
    onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0);
    @ <p><input type="submit" name="fts0" value="Delete The Full-Text Index">
    @ <input type="submit" name="fts1" value="Rebuild The Full-Text Index">
    style_submenu_element("FTS Index Debugging","%R/test-ftsdocs");
  }else{
    @ <p>The SQLite FTS4 search index is disabled.  All searching will be
    @ a full-text scan.  This usually works fine, but can be slow for
    @ larger repositories.</p>
    onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0);
    @ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
  }
Changes to src/setupuser.c.
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
48
49



50
51
52
53
54
55
56
57
58
**
**   with=CAP         Only show users that have one or more capabilities in CAP.
*/
void setup_ulist(void){
  Stmt s;
  double rNow;
  const char *zWith = P("with");


  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }

  style_submenu_element("Add", "setup_uedit");
  style_submenu_element("Log", "access_log");
  style_submenu_element("Help", "setup_ulist_notes");



  style_header("User List");
  if( zWith==0 || zWith[0]==0 ){
    @ <table border=1 cellpadding=2 cellspacing=0 class='userTable'>
    @ <thead><tr>
    @   <th>Category
    @   <th>Capabilities (<a href='%R/setup_ucap_list'>key</a>)
    @   <th>Info <th>Last Change</tr></thead>
    @ <tbody>
    db_prepare(&s,







>










>
>
>

|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
**
**   with=CAP         Only show users that have one or more capabilities in CAP.
*/
void setup_ulist(void){
  Stmt s;
  double rNow;
  const char *zWith = P("with");
  int bUnusedOnly = P("unused")!=0;

  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }

  style_submenu_element("Add", "setup_uedit");
  style_submenu_element("Log", "access_log");
  style_submenu_element("Help", "setup_ulist_notes");
  if( alert_tables_exist() ){
    style_submenu_element("Subscribers", "subscribers");
  }
  style_header("User List");
  if( (zWith==0 || zWith[0]==0) && !bUnusedOnly ){
    @ <table border=1 cellpadding=2 cellspacing=0 class='userTable'>
    @ <thead><tr>
    @   <th>Category
    @   <th>Capabilities (<a href='%R/setup_ucap_list'>key</a>)
    @   <th>Info <th>Last Change</tr></thead>
    @ <tbody>
    db_prepare(&s,
89
90
91
92
93
94
95



96
97
98
99
100
101




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








122
123
124
125
126
127
128
129
      @ </tr>
    }
    db_finalize(&s);
    @ </tbody></table>
    @ <div class='section'>Users</div>
  }else{
    style_submenu_element("All Users", "setup_ulist");



    if( zWith[1]==0 ){
      @ <div class='section'>Users with capability "%h(zWith)"</div>
    }else{
      @ <div class='section'>Users with any capability in "%h(zWith)"</div>
    }
  }




  @ <table border=1 cellpadding=2 cellspacing=0 class='userTable sortable' \
  @  data-column-types='ktxTTK' data-init-sort='2'>
  @ <thead><tr>
  @ <th>Login Name<th>Caps<th>Info<th>Date<th>Expire<th>Last Login</tr></thead>
  @ <tbody>
  db_multi_exec(
    "CREATE TEMP TABLE lastAccess(uname TEXT PRIMARY KEY, atime REAL)"
    "WITHOUT ROWID;"
  );
  if( db_table_exists("repository","accesslog") ){
    db_multi_exec(
      "INSERT INTO lastAccess(uname, atime)"
      " SELECT uname, max(mtime) FROM ("
      "    SELECT uname, mtime FROM accesslog WHERE success"
      "    UNION ALL"
      "    SELECT login AS uname, rcvfrom.mtime AS mtime"
      "      FROM rcvfrom JOIN user USING(uid))"
      " GROUP BY 1;"
    );
  }








  if( zWith && zWith[0] ){
    zWith = mprintf(" AND fullcap(cap) GLOB '*[%q]*'", zWith);
  }else{
    zWith = "";
  }
  db_prepare(&s,
     "SELECT uid, login, cap, info, date(mtime,'unixepoch'),"
     "       lower(login) AS sortkey, "







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




















>
>
>
>
>
>
>
>
|







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
      @ </tr>
    }
    db_finalize(&s);
    @ </tbody></table>
    @ <div class='section'>Users</div>
  }else{
    style_submenu_element("All Users", "setup_ulist");
    if( bUnusedOnly ){
      @ <div class='section'>Unused logins</div>
    }else if( zWith ){
      if( zWith[1]==0 ){
        @ <div class='section'>Users with capability "%h(zWith)"</div>
      }else{
        @ <div class='section'>Users with any capability in "%h(zWith)"</div>
      }
    }
  }
  if( !bUnusedOnly ){
    style_submenu_element("Unused", "setup_ulist?unused");
  }
  @ <table border=1 cellpadding=2 cellspacing=0 class='userTable sortable' \
  @  data-column-types='ktxTTK' data-init-sort='2'>
  @ <thead><tr>
  @ <th>Login Name<th>Caps<th>Info<th>Date<th>Expire<th>Last Login</tr></thead>
  @ <tbody>
  db_multi_exec(
    "CREATE TEMP TABLE lastAccess(uname TEXT PRIMARY KEY, atime REAL)"
    "WITHOUT ROWID;"
  );
  if( db_table_exists("repository","accesslog") ){
    db_multi_exec(
      "INSERT INTO lastAccess(uname, atime)"
      " SELECT uname, max(mtime) FROM ("
      "    SELECT uname, mtime FROM accesslog WHERE success"
      "    UNION ALL"
      "    SELECT login AS uname, rcvfrom.mtime AS mtime"
      "      FROM rcvfrom JOIN user USING(uid))"
      " GROUP BY 1;"
    );
  }
  if( bUnusedOnly ){
    zWith = mprintf(
        " AND login NOT IN ("
        "SELECT user FROM event WHERE user NOT NULL "
        "UNION ALL SELECT euser FROM event WHERE euser NOT NULL%s)"
        " AND uid NOT IN (SELECT uid FROM rcvfrom)",
        alert_tables_exist() ?
          " UNION ALL SELECT suname FROM subscriber WHERE suname NOT NULL":"");
  }else if( zWith && zWith[0] ){
    zWith = mprintf(" AND fullcap(cap) GLOB '*[%q]*'", zWith);
  }else{
    zWith = "";
  }
  db_prepare(&s,
     "SELECT uid, login, cap, info, date(mtime,'unixepoch'),"
     "       lower(login) AS sortkey, "
515
516
517
518
519
520
521
522

523
524
525
526
527
528
529
530
531
532









533
534
535
536
537
538
539
540
    @ <input type="hidden" name="pw" value="*">
  }
  @ <input type="hidden" name="referer" value="%h(cgi_referer("setup_ulist"))">
  @ <table width="100%%">
  @ <tr>
  @   <td class="usetupEditLabel">User ID:</td>
  if( uid ){
    @   <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" /></td>

  }else{
    @   <td>(new user)<input type="hidden" name="id" value="0" /></td>
  }
  @ </tr>
  @ <tr>
  @   <td class="usetupEditLabel">Login:</td>
  if( login_is_special(zLogin) ){
    @    <td><b>%h(zLogin)</b></td>
  }else{
    @   <td><input type="text" name="login" value="%h(zLogin)" /></td>









    @ </tr>
    @ <tr>
    @   <td class="usetupEditLabel">Contact&nbsp;Info:</td>
    @   <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
  }
  @ </tr>
  @ <tr>
  @   <td class="usetupEditLabel">Capabilities:</td>







|
>









|
>
>
>
>
>
>
>
>
>
|







534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
    @ <input type="hidden" name="pw" value="*">
  }
  @ <input type="hidden" name="referer" value="%h(cgi_referer("setup_ulist"))">
  @ <table width="100%%">
  @ <tr>
  @   <td class="usetupEditLabel">User ID:</td>
  if( uid ){
    @   <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" />\
    @ </td>
  }else{
    @   <td>(new user)<input type="hidden" name="id" value="0" /></td>
  }
  @ </tr>
  @ <tr>
  @   <td class="usetupEditLabel">Login:</td>
  if( login_is_special(zLogin) ){
    @    <td><b>%h(zLogin)</b></td>
  }else{
    @   <td><input type="text" name="login" value="%h(zLogin)" />\
    if( alert_tables_exist() ){
      int sid;
      sid = db_int(0, "SELECT subscriberId FROM subscriber"
                      " WHERE suname=%Q", zLogin);
      if( sid>0 ){
        @ &nbsp;&nbsp;<a href="%R/alerts?sid=%d(sid)">\
        @ (subscription info for %h(zLogin))</a>\
      }
    }
    @ </td></tr>
    @ <tr>
    @   <td class="usetupEditLabel">Contact&nbsp;Info:</td>
    @   <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
  }
  @ </tr>
  @ <tr>
  @   <td class="usetupEditLabel">Capabilities:</td>
548
549
550
551
552
553
554

555
556

557
558
559
560
561
562
563
  }
  @  <li><label><input type="checkbox" name="aa"%s(oa['a']) />
  @  Admin%s(B('a'))</label>
  @  <li><label><input type="checkbox" name="au"%s(oa['u']) />
  @  Reader%s(B('u'))</label>
  @  <li><label><input type="checkbox" name="av"%s(oa['v']) />
  @  Developer%s(B('v'))</label>

  @  <li><label><input type="checkbox" name="ad"%s(oa['d']) />
  @  Delete%s(B('d'))</label>

  @  <li><label><input type="checkbox" name="ae"%s(oa['e']) />
  @  View-PII%s(B('e'))</label>
  @  <li><label><input type="checkbox" name="ap"%s(oa['p']) />
  @  Password%s(B('p'))</label>
  @  <li><label><input type="checkbox" name="ai"%s(oa['i']) />
  @  Check-In%s(B('i'))</label>
  @  <li><label><input type="checkbox" name="ao"%s(oa['o']) />







>


>







577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
  }
  @  <li><label><input type="checkbox" name="aa"%s(oa['a']) />
  @  Admin%s(B('a'))</label>
  @  <li><label><input type="checkbox" name="au"%s(oa['u']) />
  @  Reader%s(B('u'))</label>
  @  <li><label><input type="checkbox" name="av"%s(oa['v']) />
  @  Developer%s(B('v'))</label>
#if 0  /* Not Used */
  @  <li><label><input type="checkbox" name="ad"%s(oa['d']) />
  @  Delete%s(B('d'))</label>
#endif
  @  <li><label><input type="checkbox" name="ae"%s(oa['e']) />
  @  View-PII%s(B('e'))</label>
  @  <li><label><input type="checkbox" name="ap"%s(oa['p']) />
  @  Password%s(B('p'))</label>
  @  <li><label><input type="checkbox" name="ai"%s(oa['i']) />
  @  Check-In%s(B('i'))</label>
  @  <li><label><input type="checkbox" name="ao"%s(oa['o']) />
623
624
625
626
627
628
629
630

631
632
633

634
635
636
637
638
639
640
  @   </td>
  @ </tr>
  if( !login_is_special(zLogin) ){
    @ <tr>
    @   <td align="right">Password:</td>
    if( zPw[0] ){
      /* Obscure the password for all users */
      @   <td><input type="password" name="pw" value="**********" /></td>

    }else{
      /* Show an empty password as an empty input field */
      @   <td><input type="password" name="pw" value="" /></td>

    }
    @ </tr>
  }
  zGroup = login_group_name();
  if( zGroup ){
    @ <tr>
    @ <td valign="top" align="right">Scope:</td>







|
>


|
>







654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
  @   </td>
  @ </tr>
  if( !login_is_special(zLogin) ){
    @ <tr>
    @   <td align="right">Password:</td>
    if( zPw[0] ){
      /* Obscure the password for all users */
      @   <td><input type="password" autocomplete="off" name="pw"\
      @   value="**********" /></td>
    }else{
      /* Show an empty password as an empty input field */
      @   <td><input type="password" autocomplete="off" name="pw"\
      @   value="" /></td>
    }
    @ </tr>
  }
  zGroup = login_group_name();
  if( zGroup ){
    @ <tr>
    @ <td valign="top" align="right">Scope:</td>
Changes to src/shell.c.
31
32
33
34
35
36
37








38
39
40
41
42
43
44
** utility for accessing SQLite databases.
*/
#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
/* This needs to come before any includes for MSVC compiler */
#define _CRT_SECURE_NO_WARNINGS
#endif









/*
** Warning pragmas copied from msvc.h in the core.
*/
#if defined(_MSC_VER)
#pragma warning(disable : 4054)
#pragma warning(disable : 4055)
#pragma warning(disable : 4100)







>
>
>
>
>
>
>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
** utility for accessing SQLite databases.
*/
#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
/* This needs to come before any includes for MSVC compiler */
#define _CRT_SECURE_NO_WARNINGS
#endif

/*
** Determine if we are dealing with WinRT, which provides only a subset of
** the full Win32 API.
*/
#if !defined(SQLITE_OS_WINRT)
# define SQLITE_OS_WINRT 0
#endif

/*
** Warning pragmas copied from msvc.h in the core.
*/
#if defined(_MSC_VER)
#pragma warning(disable : 4054)
#pragma warning(disable : 4055)
#pragma warning(disable : 4100)
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
# define shell_stifle_history(X)

# define SHELL_USE_LOCAL_GETLINE 1
#endif


#if defined(_WIN32) || defined(WIN32)



# include <io.h>
# include <fcntl.h>
# define isatty(h) _isatty(h)
# ifndef access
#  define access(f,m) _access((f),(m))
# endif
# ifndef unlink
#  define unlink _unlink
# endif
# ifndef strdup
#  define strdup _strdup
# endif
# undef popen
# define popen _popen
# undef pclose
# define pclose _pclose

#else
 /* Make sure isatty() has a prototype. */
 extern int isatty(int);

# if !defined(__RTP__) && !defined(_WRS_KERNEL)
  /* popen and pclose are not C89 functions and so are
  ** sometimes omitted from the <stdio.h> header */







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







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# define shell_stifle_history(X)

# define SHELL_USE_LOCAL_GETLINE 1
#endif


#if defined(_WIN32) || defined(WIN32)
# if SQLITE_OS_WINRT
#  define SQLITE_OMIT_POPEN 1
# else
#  include <io.h>
#  include <fcntl.h>
#  define isatty(h) _isatty(h)
#  ifndef access
#   define access(f,m) _access((f),(m))
#  endif
#  ifndef unlink
#   define unlink _unlink
#  endif
#  ifndef strdup
#   define strdup _strdup
#  endif
#  undef popen
#  define popen _popen
#  undef pclose
#  define pclose _pclose
# endif
#else
 /* Make sure isatty() has a prototype. */
 extern int isatty(int);

# if !defined(__RTP__) && !defined(_WRS_KERNEL)
  /* popen and pclose are not C89 functions and so are
  ** sometimes omitted from the <stdio.h> header */
187
188
189
190
191
192
193



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

/* ctype macros that work with signed characters */
#define IsSpace(X)  isspace((unsigned char)X)
#define IsDigit(X)  isdigit((unsigned char)X)
#define ToLower(X)  (char)tolower((unsigned char)X)

#if defined(_WIN32) || defined(WIN32)



#include <windows.h>

/* string conversion routines only needed on Win32 */
extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
#endif

/* On Windows, we normally run with output mode of TEXT so that \n characters
** are automatically translated into \r\n.  However, this behavior needs
** to be disabled in some cases (ex: when generating CSV output and when
** rendering quoted strings that contain \n characters).  The following
** routines take care of that.
*/
#if defined(_WIN32) || defined(WIN32)
static void setBinaryMode(FILE *file, int isOutput){
  if( isOutput ) fflush(file);
  _setmode(_fileno(file), _O_BINARY);
}
static void setTextMode(FILE *file, int isOutput){
  if( isOutput ) fflush(file);
  _setmode(_fileno(file), _O_TEXT);







>
>
>















|







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231

/* ctype macros that work with signed characters */
#define IsSpace(X)  isspace((unsigned char)X)
#define IsDigit(X)  isdigit((unsigned char)X)
#define ToLower(X)  (char)tolower((unsigned char)X)

#if defined(_WIN32) || defined(WIN32)
#if SQLITE_OS_WINRT
#include <intrin.h>
#endif
#include <windows.h>

/* string conversion routines only needed on Win32 */
extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
#endif

/* On Windows, we normally run with output mode of TEXT so that \n characters
** are automatically translated into \r\n.  However, this behavior needs
** to be disabled in some cases (ex: when generating CSV output and when
** rendering quoted strings that contain \n characters).  The following
** routines take care of that.
*/
#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
static void setBinaryMode(FILE *file, int isOutput){
  if( isOutput ) fflush(file);
  _setmode(_fileno(file), _O_BINARY);
}
static void setTextMode(FILE *file, int isOutput){
  if( isOutput ) fflush(file);
  _setmode(_fileno(file), _O_TEXT);
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
** Check to see if we have timer support.  Return 1 if necessary
** support found (or found previously).
*/
static int hasTimer(void){
  if( getProcessTimesAddr ){
    return 1;
  } else {

    /* GetProcessTimes() isn't supported in WIN95 and some other Windows
    ** versions. See if the version we are running on has it, and if it
    ** does, save off a pointer to it and the current process handle.
    */
    hProcess = GetCurrentProcess();
    if( hProcess ){
      HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
      if( NULL != hinstLib ){
        getProcessTimesAddr =
            (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
        if( NULL != getProcessTimesAddr ){
          return 1;
        }
        FreeLibrary(hinstLib);
      }
    }

  }
  return 0;
}

/*
** Begin timing an operation
*/







>
















>







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
** Check to see if we have timer support.  Return 1 if necessary
** support found (or found previously).
*/
static int hasTimer(void){
  if( getProcessTimesAddr ){
    return 1;
  } else {
#if !SQLITE_OS_WINRT
    /* GetProcessTimes() isn't supported in WIN95 and some other Windows
    ** versions. See if the version we are running on has it, and if it
    ** does, save off a pointer to it and the current process handle.
    */
    hProcess = GetCurrentProcess();
    if( hProcess ){
      HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
      if( NULL != hinstLib ){
        getProcessTimesAddr =
            (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
        if( NULL != getProcessTimesAddr ){
          return 1;
        }
        FreeLibrary(hinstLib);
      }
    }
#endif
  }
  return 0;
}

/*
** Begin timing an operation
*/
411
412
413
414
415
416
417









418
419
420
421
422
423
424
static sqlite3 *globalDb = 0;

/*
** True if an interrupt (Control-C) has been received.
*/
static volatile int seenInterrupt = 0;










/*
** This is the name of our program. It is set in main(), used
** in a number of other places, mostly for error messages.
*/
static char *Argv0;

/*







>
>
>
>
>
>
>
>
>







428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
static sqlite3 *globalDb = 0;

/*
** True if an interrupt (Control-C) has been received.
*/
static volatile int seenInterrupt = 0;

#ifdef SQLITE_DEBUG
/*
** Out-of-memory simulator variables
*/
static unsigned int oomCounter = 0;    /* Simulate OOM when equals 1 */
static unsigned int oomRepeat = 0;     /* Number of OOMs in a row */
static void*(*defaultMalloc)(int) = 0; /* The low-level malloc routine */
#endif /* SQLITE_DEBUG */

/*
** This is the name of our program. It is set in main(), used
** in a number of other places, mostly for error messages.
*/
static char *Argv0;

/*
461
462
463
464
465
466
467











































468
469
470
471
472
473
474
#endif

/* Indicate out-of-memory and exit. */
static void shell_out_of_memory(void){
  raw_printf(stderr,"Error: out of memory\n");
  exit(1);
}












































/*
** Write I/O traces to the following stream.
*/
#ifdef SQLITE_ENABLE_IOTRACE
static FILE *iotrace = 0;
#endif







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







487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
#endif

/* Indicate out-of-memory and exit. */
static void shell_out_of_memory(void){
  raw_printf(stderr,"Error: out of memory\n");
  exit(1);
}

#ifdef SQLITE_DEBUG
/* This routine is called when a simulated OOM occurs.  It is broken
** out as a separate routine to make it easy to set a breakpoint on
** the OOM
*/
void shellOomFault(void){
  if( oomRepeat>0 ){
    oomRepeat--;
  }else{
    oomCounter--;
  }
}
#endif /* SQLITE_DEBUG */

#ifdef SQLITE_DEBUG
/* This routine is a replacement malloc() that is used to simulate
** Out-Of-Memory (OOM) errors for testing purposes.
*/
static void *oomMalloc(int nByte){
  if( oomCounter ){
    if( oomCounter==1 ){
      shellOomFault();
      return 0;
    }else{
      oomCounter--;
    }
  }
  return defaultMalloc(nByte);
}
#endif /* SQLITE_DEBUG */

#ifdef SQLITE_DEBUG
/* Register the OOM simulator.  This must occur before any memory
** allocations */
static void registerOomSimulator(void){
  sqlite3_mem_methods mem;
  sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mem);
  defaultMalloc = mem.xMalloc;
  mem.xMalloc = oomMalloc;
  sqlite3_config(SQLITE_CONFIG_MALLOC, &mem);
}
#endif

/*
** Write I/O traces to the following stream.
*/
#ifdef SQLITE_ENABLE_IOTRACE
static FILE *iotrace = 0;
#endif
2003
2004
2005
2006
2007
2008
2009
2010

2011
2012
2013

2014
2015
2016
2017

2018
2019
2020
2021

2022
2023
2024
2025
2026
2027
2028
2029
  sqlite3 *db,
  char **pzErrMsg,
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,

                               sha3Func, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,

                                 sha3Func, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,

                                 sha3QueryFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,

                                 sha3QueryFunc, 0, 0);
  }
  return rc;
}

/************************* End ../ext/misc/shathree.c ********************/
/************************* Begin ../ext/misc/fileio.c ******************/
/*







|
>
|

|
>
|


|
>
|


|
>
|







2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
  sqlite3 *db,
  char **pzErrMsg,
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "sha3", 1,
                      SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
                      0, sha3Func, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sha3", 2,
                      SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
                      0, sha3Func, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sha3_query", 1,
                      SQLITE_UTF8 | SQLITE_DIRECTONLY,
                      0, sha3QueryFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sha3_query", 2,
                      SQLITE_UTF8 | SQLITE_DIRECTONLY,
                      0, sha3QueryFunc, 0, 0);
  }
  return rc;
}

/************************* End ../ext/misc/shathree.c ********************/
/************************* Begin ../ext/misc/fileio.c ******************/
/*
2418
2419
2420
2421
2422
2423
2424

2425
2426
2427
2428
2429
2430
2431
      if( rc ) return 2;
      sqlite3_result_int64(pCtx, nWrite);
    }
  }

  if( mtime>=0 ){
#if defined(_WIN32)

    /* Windows */
    FILETIME lastAccess;
    FILETIME lastWrite;
    SYSTEMTIME currentTime;
    LONGLONG intervals;
    HANDLE hFile;
    LPWSTR zUnicodeName;







>







2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
      if( rc ) return 2;
      sqlite3_result_int64(pCtx, nWrite);
    }
  }

  if( mtime>=0 ){
#if defined(_WIN32)
#if !SQLITE_OS_WINRT
    /* Windows */
    FILETIME lastAccess;
    FILETIME lastWrite;
    SYSTEMTIME currentTime;
    LONGLONG intervals;
    HANDLE hFile;
    LPWSTR zUnicodeName;
2448
2449
2450
2451
2452
2453
2454

2455
2456
2457
2458
2459
2460
2461
    if( hFile!=INVALID_HANDLE_VALUE ){
      BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
      CloseHandle(hFile);
      return !bResult;
    }else{
      return 1;
    }

#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
    /* Recent unix */
    struct timespec times[2];
    times[0].tv_nsec = times[1].tv_nsec = 0;
    times[0].tv_sec = time(0);
    times[1].tv_sec = mtime;
    if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){







>







2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
    if( hFile!=INVALID_HANDLE_VALUE ){
      BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
      CloseHandle(hFile);
      return !bResult;
    }else{
      return 1;
    }
#endif
#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
    /* Recent unix */
    struct timespec times[2];
    times[0].tv_nsec = times[1].tv_nsec = 0;
    times[0].tv_sec = time(0);
    times[1].tv_sec = mtime;
    if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
2609
2610
2611
2612
2613
2614
2615

2616
2617
2618
2619
2620
2621
2622
  (void)argv;
  (void)pzErr;
  rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
  if( rc==SQLITE_OK ){
    pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, sizeof(*pNew));

  }
  *ppVtab = (sqlite3_vtab*)pNew;
  return rc;
}

/*
** This method is the destructor for fsdir vtab objects.







>







2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
  (void)argv;
  (void)pzErr;
  rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
  if( rc==SQLITE_OK ){
    pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, sizeof(*pNew));
    sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
  }
  *ppVtab = (sqlite3_vtab*)pNew;
  return rc;
}

/*
** This method is the destructor for fsdir vtab objects.
3002
3003
3004
3005
3006
3007
3008
3009

3010
3011
3012

3013
3014
3015
3016
3017
3018
3019
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,

                               readfileFunc, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,

                                 writefileFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
                                 lsModeFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){







|
>


|
>







3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "readfile", 1, 
                               SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
                               readfileFunc, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "writefile", -1,
                                 SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
                                 writefileFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
                                 lsModeFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
3140
3141
3142
3143
3144
3145
3146

3147
3148
3149
3150
3151
3152
3153

/* Column numbers */
#define COMPLETION_COLUMN_CANDIDATE 0  /* Suggested completion of the input */
#define COMPLETION_COLUMN_PREFIX    1  /* Prefix of the word to be completed */
#define COMPLETION_COLUMN_WHOLELINE 2  /* Entire line seen so far */
#define COMPLETION_COLUMN_PHASE     3  /* ePhase - used for debugging only */


  rc = sqlite3_declare_vtab(db,
      "CREATE TABLE x("
      "  candidate TEXT,"
      "  prefix TEXT HIDDEN,"
      "  wholeline TEXT HIDDEN,"
      "  phase INT HIDDEN"        /* Used for debugging only */
      ")");







>







3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232

/* Column numbers */
#define COMPLETION_COLUMN_CANDIDATE 0  /* Suggested completion of the input */
#define COMPLETION_COLUMN_PREFIX    1  /* Prefix of the word to be completed */
#define COMPLETION_COLUMN_WHOLELINE 2  /* Entire line seen so far */
#define COMPLETION_COLUMN_PHASE     3  /* ePhase - used for debugging only */

  sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
  rc = sqlite3_declare_vtab(db,
      "CREATE TABLE x("
      "  candidate TEXT,"
      "  prefix TEXT HIDDEN,"
      "  wholeline TEXT HIDDEN,"
      "  phase INT HIDDEN"        /* Used for debugging only */
      ")");
4201
4202
4203
4204
4205
4206
4207






























































































4208
4209
4210
4211
4212
4213
4214
    }
  }
  memtraceOut = 0;
  return rc;
}

/************************* End ../ext/misc/memtrace.c ********************/






























































































#ifdef SQLITE_HAVE_ZLIB
/************************* Begin ../ext/misc/zipfile.c ******************/
/*
** 2017-12-26
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:







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







4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
    }
  }
  memtraceOut = 0;
  return rc;
}

/************************* End ../ext/misc/memtrace.c ********************/
/************************* Begin ../ext/misc/uint.c ******************/
/*
** 2020-04-14
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
******************************************************************************
**
** This SQLite extension implements the UINT collating sequence.
**
** UINT works like BINARY for text, except that embedded strings
** of digits compare in numeric order.
**
**     *   Leading zeros are handled properly, in the sense that
**         they do not mess of the maginitude comparison of embedded
**         strings of digits.  "x00123y" is equal to "x123y".
**
**     *   Only unsigned integers are recognized.  Plus and minus
**         signs are ignored.  Decimal points and exponential notation
**         are ignored.
**
**     *   Embedded integers can be of arbitrary length.  Comparison
**         is *not* limited integers that can be expressed as a
**         64-bit machine integer.
*/
/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <ctype.h>

/*
** Compare text in lexicographic order, except strings of digits
** compare in numeric order.
*/
static int uintCollFunc(
  void *notUsed,
  int nKey1, const void *pKey1,
  int nKey2, const void *pKey2
){
  const unsigned char *zA = (const unsigned char*)pKey1;
  const unsigned char *zB = (const unsigned char*)pKey2;
  int i=0, j=0, x;
  while( i<nKey1 && j<nKey2 ){
    x = zA[i] - zB[j];
    if( isdigit(zA[i]) ){
      int k;
      if( !isdigit(zB[j]) ) return x;
      while( i<nKey1 && zA[i]=='0' ){ i++; }
      while( j<nKey2 && zB[j]=='0' ){ j++; }
      k = 0;
      while( i+k<nKey1 && isdigit(zA[i+k])
             && j+k<nKey2 && isdigit(zB[j+k]) ){
        k++;
      }
      if( i+k<nKey1 && isdigit(zA[i+k]) ){
        return +1;
      }else if( j+k<nKey2 && isdigit(zB[j+k]) ){
        return -1;
      }else{
        x = memcmp(zA+i, zB+j, k);
        if( x ) return x;
        i += k;
        j += k;
      }
    }else if( x ){
      return x;
    }else{
      i++;
      j++;
    }
  }
  return (nKey1 - i) - (nKey2 - j);
}

#ifdef _WIN32

#endif
int sqlite3_uint_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc);
}

/************************* End ../ext/misc/uint.c ********************/
#ifdef SQLITE_HAVE_ZLIB
/************************* Begin ../ext/misc/zipfile.c ******************/
/*
** 2017-12-26
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
4574
4575
4576
4577
4578
4579
4580

4581
4582
4583
4584
4585
4586
4587
    pNew->aBuffer = (u8*)&pNew[1];
    if( zFile ){
      pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE];
      memcpy(pNew->zFile, zFile, nFile);
      zipfileDequote(pNew->zFile);
    }
  }

  *ppVtab = (sqlite3_vtab*)pNew;
  return rc;
}

/*
** Free the ZipfileEntry structure indicated by the only argument.
*/







>







4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
    pNew->aBuffer = (u8*)&pNew[1];
    if( zFile ){
      pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE];
      memcpy(pNew->zFile, zFile, nFile);
      zipfileDequote(pNew->zFile);
    }
  }
  sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
  *ppVtab = (sqlite3_vtab*)pNew;
  return rc;
}

/*
** Free the ZipfileEntry structure indicated by the only argument.
*/
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
  aOut = (u8*)sqlite3_malloc64(nAlloc);
  if( aOut==0 ){
    rc = SQLITE_NOMEM;
  }else{
    int res;
    str.next_out = aOut;
    str.avail_out = nAlloc;
    deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
    res = deflate(&str, Z_FINISH);
    if( res==Z_STREAM_END ){
      *ppOut = aOut;
      *pnOut = (int)str.total_out;
    }else{
      sqlite3_free(aOut);
      *pzErr = sqlite3_mprintf("zipfile: deflate() error");







<







5378
5379
5380
5381
5382
5383
5384

5385
5386
5387
5388
5389
5390
5391
  aOut = (u8*)sqlite3_malloc64(nAlloc);
  if( aOut==0 ){
    rc = SQLITE_NOMEM;
  }else{
    int res;
    str.next_out = aOut;
    str.avail_out = nAlloc;

    res = deflate(&str, Z_FINISH);
    if( res==Z_STREAM_END ){
      *ppOut = aOut;
      *pnOut = (int)str.total_out;
    }else{
      sqlite3_free(aOut);
      *pzErr = sqlite3_mprintf("zipfile: deflate() error");
5514
5515
5516
5517
5518
5519
5520

5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
    if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
    if( pCons->usable==0 ){
      unusable = 1;
    }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
      idx = i;
    }
  }

  if( idx>=0 ){
    pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
    pIdxInfo->aConstraintUsage[idx].omit = 1;
    pIdxInfo->estimatedCost = 1000.0;
    pIdxInfo->idxNum = 1;
  }else if( unusable ){
    return SQLITE_CONSTRAINT;
  }
  return SQLITE_OK;
}








>



<







5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697

5698
5699
5700
5701
5702
5703
5704
    if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
    if( pCons->usable==0 ){
      unusable = 1;
    }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
      idx = i;
    }
  }
  pIdxInfo->estimatedCost = 1000.0;
  if( idx>=0 ){
    pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
    pIdxInfo->aConstraintUsage[idx].omit = 1;

    pIdxInfo->idxNum = 1;
  }else if( unusable ){
    return SQLITE_CONSTRAINT;
  }
  return SQLITE_OK;
}

5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656




5657
5658
5659
5660
5661
5662
5663

/*
** Both (const char*) arguments point to nul-terminated strings. Argument
** nB is the value of strlen(zB). This function returns 0 if the strings are
** identical, ignoring any trailing '/' character in either path.  */
static int zipfileComparePath(const char *zA, const char *zB, int nB){
  int nA = (int)strlen(zA);
  if( zA[nA-1]=='/' ) nA--;
  if( zB[nB-1]=='/' ) nB--;
  if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
  return 1;
}

static int zipfileBegin(sqlite3_vtab *pVtab){
  ZipfileTab *pTab = (ZipfileTab*)pVtab;
  int rc = SQLITE_OK;

  assert( pTab->pWriteFd==0 );





  /* Open a write fd on the file. Also load the entire central directory
  ** structure into memory. During the transaction any new file data is 
  ** appended to the archive file, but the central directory is accumulated
  ** in main-memory until the transaction is committed.  */
  pTab->pWriteFd = fopen(pTab->zFile, "ab+");
  if( pTab->pWriteFd==0 ){







|
|









>
>
>
>







5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840

/*
** Both (const char*) arguments point to nul-terminated strings. Argument
** nB is the value of strlen(zB). This function returns 0 if the strings are
** identical, ignoring any trailing '/' character in either path.  */
static int zipfileComparePath(const char *zA, const char *zB, int nB){
  int nA = (int)strlen(zA);
  if( nA>0 && zA[nA-1]=='/' ) nA--;
  if( nB>0 && zB[nB-1]=='/' ) nB--;
  if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
  return 1;
}

static int zipfileBegin(sqlite3_vtab *pVtab){
  ZipfileTab *pTab = (ZipfileTab*)pVtab;
  int rc = SQLITE_OK;

  assert( pTab->pWriteFd==0 );
  if( pTab->zFile==0 || pTab->zFile[0]==0 ){
    pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename");
    return SQLITE_ERROR;
  }

  /* Open a write fd on the file. Also load the entire central directory
  ** structure into memory. During the transaction any new file data is 
  ** appended to the archive file, but the central directory is accumulated
  ** in main-memory until the transaction is committed.  */
  pTab->pWriteFd = fopen(pTab->zFile, "ab+");
  if( pTab->pWriteFd==0 ){
5824
5825
5826
5827
5828
5829
5830

5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843


5844



5845
5846
5847
5848
5849
5850
5851

    if( rc==SQLITE_OK ){
      rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg);
    }

    if( rc==SQLITE_OK ){
      zPath = (const char*)sqlite3_value_text(apVal[2]);

      nPath = (int)strlen(zPath);
      mTime = zipfileGetTime(apVal[4]);
    }

    if( rc==SQLITE_OK && bIsDir ){
      /* For a directory, check that the last character in the path is a
      ** '/'. This appears to be required for compatibility with info-zip
      ** (the unzip command on unix). It does not create directories
      ** otherwise.  */
      if( zPath[nPath-1]!='/' ){
        zFree = sqlite3_mprintf("%s/", zPath);
        if( zFree==0 ){ rc = SQLITE_NOMEM; }
        zPath = (const char*)zFree;


        nPath++;



      }
    }

    /* Check that we're not inserting a duplicate entry -OR- updating an
    ** entry with a path, thereby making it into a duplicate. */
    if( (pOld==0 || bUpdate) && rc==SQLITE_OK ){
      ZipfileEntry *p;







>









|

<

>
>
|
>
>
>







6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019

6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033

    if( rc==SQLITE_OK ){
      rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg);
    }

    if( rc==SQLITE_OK ){
      zPath = (const char*)sqlite3_value_text(apVal[2]);
      if( zPath==0 ) zPath = "";
      nPath = (int)strlen(zPath);
      mTime = zipfileGetTime(apVal[4]);
    }

    if( rc==SQLITE_OK && bIsDir ){
      /* For a directory, check that the last character in the path is a
      ** '/'. This appears to be required for compatibility with info-zip
      ** (the unzip command on unix). It does not create directories
      ** otherwise.  */
      if( nPath<=0 || zPath[nPath-1]!='/' ){
        zFree = sqlite3_mprintf("%s/", zPath);

        zPath = (const char*)zFree;
        if( zFree==0 ){
          rc = SQLITE_NOMEM;
          nPath = 0;
        }else{
          nPath = (int)strlen(zPath);
        }
      }
    }

    /* Check that we're not inserting a duplicate entry -OR- updating an
    ** entry with a path, thereby making it into a duplicate. */
    if( (pOld==0 || bUpdate) && rc==SQLITE_OK ){
      ZipfileEntry *p;
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249

6250
6251
6252
6253
6254
6255
6256
  /* Decode the "mtime" argument. */
  e.mUnixTime = zipfileGetTime(pMtime);

  /* If this is a directory entry, ensure that there is exactly one '/'
  ** at the end of the path. Or, if this is not a directory and the path
  ** ends in '/' it is an error. */
  if( bIsDir==0 ){
    if( zName[nName-1]=='/' ){
      zErr = sqlite3_mprintf("non-directory name must not end with /");
      rc = SQLITE_ERROR;
      goto zipfile_step_out;
    }
  }else{
    if( zName[nName-1]!='/' ){
      zName = zFree = sqlite3_mprintf("%s/", zName);
      nName++;
      if( zName==0 ){
        rc = SQLITE_NOMEM;
        goto zipfile_step_out;
      }

    }else{
      while( nName>1 && zName[nName-2]=='/' ) nName--;
    }
  }

  /* Assemble the ZipfileEntry object for the new zip archive entry */
  e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;







|





|

<




>







6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426

6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
  /* Decode the "mtime" argument. */
  e.mUnixTime = zipfileGetTime(pMtime);

  /* If this is a directory entry, ensure that there is exactly one '/'
  ** at the end of the path. Or, if this is not a directory and the path
  ** ends in '/' it is an error. */
  if( bIsDir==0 ){
    if( nName>0 && zName[nName-1]=='/' ){
      zErr = sqlite3_mprintf("non-directory name must not end with /");
      rc = SQLITE_ERROR;
      goto zipfile_step_out;
    }
  }else{
    if( nName==0 || zName[nName-1]!='/' ){
      zName = zFree = sqlite3_mprintf("%s/", zName);

      if( zName==0 ){
        rc = SQLITE_NOMEM;
        goto zipfile_step_out;
      }
      nName = (int)strlen(zName);
    }else{
      while( nName>1 && zName[nName-2]=='/' ) nName--;
    }
  }

  /* Assemble the ZipfileEntry object for the new zip archive entry */
  e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
6498
6499
6500
6501
6502
6503
6504
6505

6506
6507
6508

6509
6510
6511
6512
6513
6514
6515
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,

                               sqlarCompressFunc, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,

                                 sqlarUncompressFunc, 0, 0);
  }
  return rc;
}

/************************* End ../ext/misc/sqlar.c ********************/
#endif







|
>


|
>







6680
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "sqlar_compress", 1, 
                               SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
                               sqlarCompressFunc, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sqlar_uncompress", 2,
                                 SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
                                 sqlarUncompressFunc, 0, 0);
  }
  return rc;
}

/************************* End ../ext/misc/sqlar.c ********************/
#endif
9579
9580
9581
9582
9583
9584
9585

9586
9587
9588
9589
9590
9591
9592
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
  int showHeader;        /* True to show column names in List or Column mode */
  int nCheck;            /* Number of ".check" commands run */
  unsigned nProgress;    /* Number of progress callbacks encountered */
  unsigned mxProgress;   /* Maximum progress callbacks before failing */
  unsigned flgProgress;  /* Flags for the progress callback */
  unsigned shellFlgs;    /* Various flags */

  sqlite3_int64 szMax;   /* --maxsize argument to .open */
  char *zDestTable;      /* Name of destination table when MODE_Insert */
  char *zTempFile;       /* Temporary file that might need deleting */
  char zTestcase[30];    /* Name of current test case */
  char colSeparator[20]; /* Column separator character for several modes */
  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
  char colSepPrior[20];  /* Saved column separator */







>







9763
9764
9765
9766
9767
9768
9769
9770
9771
9772
9773
9774
9775
9776
9777
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
  int showHeader;        /* True to show column names in List or Column mode */
  int nCheck;            /* Number of ".check" commands run */
  unsigned nProgress;    /* Number of progress callbacks encountered */
  unsigned mxProgress;   /* Maximum progress callbacks before failing */
  unsigned flgProgress;  /* Flags for the progress callback */
  unsigned shellFlgs;    /* Various flags */
  unsigned priorShFlgs;  /* Saved copy of flags */
  sqlite3_int64 szMax;   /* --maxsize argument to .open */
  char *zDestTable;      /* Name of destination table when MODE_Insert */
  char *zTempFile;       /* Temporary file that might need deleting */
  char zTestcase[30];    /* Name of current test case */
  char colSeparator[20]; /* Column separator character for several modes */
  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
  char colSepPrior[20];  /* Saved column separator */
9879
9880
9881
9882
9883
9884
9885

9886
9887
9888
9889
9890

9891
9892
9893
9894
9895
9896
9897
#endif /* SQLITE_NOHAVE_SYSTEM */

/*
** Save or restore the current output mode
*/
static void outputModePush(ShellState *p){
  p->modePrior = p->mode;

  memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
  memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
}
static void outputModePop(ShellState *p){
  p->mode = p->modePrior;

  memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
  memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
}

/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/







>





>







10064
10065
10066
10067
10068
10069
10070
10071
10072
10073
10074
10075
10076
10077
10078
10079
10080
10081
10082
10083
10084
#endif /* SQLITE_NOHAVE_SYSTEM */

/*
** Save or restore the current output mode
*/
static void outputModePush(ShellState *p){
  p->modePrior = p->mode;
  p->priorShFlgs = p->shellFlgs;
  memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
  memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
}
static void outputModePop(ShellState *p){
  p->mode = p->modePrior;
  p->shellFlgs = p->priorShFlgs;
  memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
  memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
}

/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
10848
10849
10850
10851
10852
10853
10854
10855
10856
10857
10858
10859
10860
10861
10862
10863
10864
10865
10866
10867
10868
10869
10870
10871
10872
10873
10874
10875
10876
10877
10878
10879
10880
10881
10882
10883
** If the number of columns is 1 and that column contains text "--"
** then write the semicolon on a separate line.  That way, if a
** "--" comment occurs at the end of the statement, the comment
** won't consume the semicolon terminator.
*/
static int run_table_dump_query(
  ShellState *p,           /* Query context */
  const char *zSelect,     /* SELECT statement to extract content */
  const char *zFirstRow    /* Print before first row, if not NULL */
){
  sqlite3_stmt *pSelect;
  int rc;
  int nResult;
  int i;
  const char *z;
  rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
  if( rc!=SQLITE_OK || !pSelect ){
    utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
                sqlite3_errmsg(p->db));
    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    return rc;
  }
  rc = sqlite3_step(pSelect);
  nResult = sqlite3_column_count(pSelect);
  while( rc==SQLITE_ROW ){
    if( zFirstRow ){
      utf8_printf(p->out, "%s", zFirstRow);
      zFirstRow = 0;
    }
    z = (const char*)sqlite3_column_text(pSelect, 0);
    utf8_printf(p->out, "%s", z);
    for(i=1; i<nResult; i++){
      utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
    }
    if( z==0 ) z = "";
    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;







|
<
















<
<
<
<







11035
11036
11037
11038
11039
11040
11041
11042

11043
11044
11045
11046
11047
11048
11049
11050
11051
11052
11053
11054
11055
11056
11057
11058




11059
11060
11061
11062
11063
11064
11065
** If the number of columns is 1 and that column contains text "--"
** then write the semicolon on a separate line.  That way, if a
** "--" comment occurs at the end of the statement, the comment
** won't consume the semicolon terminator.
*/
static int run_table_dump_query(
  ShellState *p,           /* Query context */
  const char *zSelect      /* SELECT statement to extract content */

){
  sqlite3_stmt *pSelect;
  int rc;
  int nResult;
  int i;
  const char *z;
  rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
  if( rc!=SQLITE_OK || !pSelect ){
    utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
                sqlite3_errmsg(p->db));
    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    return rc;
  }
  rc = sqlite3_step(pSelect);
  nResult = sqlite3_column_count(pSelect);
  while( rc==SQLITE_ROW ){




    z = (const char*)sqlite3_column_text(pSelect, 0);
    utf8_printf(p->out, "%s", z);
    for(i=1; i<nResult; i++){
      utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
    }
    if( z==0 ) z = "";
    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
11303
11304
11305
11306
11307
11308
11309



11310
11311
11312
11313
11314
11315
11316
11317
11318

11319
11320
11321
11322
11323
11324
11325
11326
11327
11328
11329
11330
11331
11332
11333
11334
11335
11336
11337
11338
  sqlite3WhereTrace = savedWhereTrace;
#endif
}

/* Create the TEMP table used to store parameter bindings */
static void bind_table_init(ShellState *p){
  int wrSchema = 0;



  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema);
  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
  sqlite3_exec(p->db,
    "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n"
    "  key TEXT PRIMARY KEY,\n"
    "  value ANY\n"
    ") WITHOUT ROWID;",
    0, 0, 0);
  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0);

}

/*
** Bind parameters on a prepared statement.
**
** Parameter bindings are taken from a TEMP table of the form:
**
**    CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value)
**    WITHOUT ROWID;
**
** No bindings occur if this table does not exist.  The special character '$'
** is included in the table name to help prevent collisions with actual tables.
** The table must be in the TEMP schema.
*/
static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
  int nVar;
  int i;
  int rc;
  sqlite3_stmt *pQ = 0;








>
>
>









>










|
|
|







11485
11486
11487
11488
11489
11490
11491
11492
11493
11494
11495
11496
11497
11498
11499
11500
11501
11502
11503
11504
11505
11506
11507
11508
11509
11510
11511
11512
11513
11514
11515
11516
11517
11518
11519
11520
11521
11522
11523
11524
  sqlite3WhereTrace = savedWhereTrace;
#endif
}

/* Create the TEMP table used to store parameter bindings */
static void bind_table_init(ShellState *p){
  int wrSchema = 0;
  int defensiveMode = 0;
  sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &defensiveMode);
  sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema);
  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
  sqlite3_exec(p->db,
    "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n"
    "  key TEXT PRIMARY KEY,\n"
    "  value ANY\n"
    ") WITHOUT ROWID;",
    0, 0, 0);
  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0);
  sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0);
}

/*
** Bind parameters on a prepared statement.
**
** Parameter bindings are taken from a TEMP table of the form:
**
**    CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value)
**    WITHOUT ROWID;
**
** No bindings occur if this table does not exist.  The name of the table
** begins with "sqlite_" so that it will not collide with ordinary application
** tables.  The table must be in the TEMP schema.
*/
static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
  int nVar;
  int i;
  int rc;
  sqlite3_stmt *pQ = 0;

12038
12039
12040
12041
12042
12043
12044
12045
12046
12047
12048
12049

12050
12051
12052
12053
12054
12055
12056
12057
12058

12059
12060
12061
12062

12063
12064
12065
12066
12067












12068
12069
12070
12071
12072
12073
12074
  ".cd DIRECTORY            Change the working directory to DIRECTORY",
  ".changes on|off          Show number of rows changed by SQL",
  ".check GLOB              Fail if output since .testcase does not match",
  ".clone NEWDB             Clone data into NEWDB from the existing database",
  ".databases               List names and files of attached databases",
  ".dbconfig ?op? ?val?     List or change sqlite3_db_config() options",
  ".dbinfo ?DB?             Show status information about the database",
  ".dump ?TABLE? ...        Render all database content as SQL",
  "   Options:",
  "     --preserve-rowids      Include ROWID values in the output",
  "     --newlines             Allow unescaped newline characters in output",
  "   TABLE is a LIKE pattern for the tables to dump",

  ".echo on|off             Turn command echo on or off",
  ".eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN",
  "   Other Modes:",
#ifdef SQLITE_DEBUG
  "      test                  Show raw EXPLAIN QUERY PLAN output",
  "      trace                 Like \"full\" but enable \"PRAGMA vdbe_trace\"",
#endif
  "      trigger               Like \"full\" but also show trigger bytecode",
  ".excel                   Display the output of next command in spreadsheet",

  ".exit ?CODE?             Exit this program with return-code CODE",
  ".expert                  EXPERIMENTAL. Suggest indexes for queries",
  ".explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto",
  ".filectrl CMD ...        Run various sqlite3_file_control() operations",

  "                           Run \".filectrl\" with no arguments for details",
  ".fullschema ?--indent?   Show schema and the content of sqlite_stat tables",
  ".headers on|off          Turn display of headers on or off",
  ".help ?-all? ?PATTERN?   Show help text for PATTERN",
  ".import FILE TABLE       Import data from FILE into TABLE",












#ifndef SQLITE_OMIT_TEST_CONTROL
  ".imposter INDEX TABLE    Create imposter table TABLE on index INDEX",
#endif
  ".indexes ?TABLE?         Show names of indexes",
  "                           If TABLE is specified, only show indexes for",
  "                           tables matching TABLE using the LIKE operator.",
#ifdef SQLITE_ENABLE_IOTRACE







|




>









>




>
|




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







12224
12225
12226
12227
12228
12229
12230
12231
12232
12233
12234
12235
12236
12237
12238
12239
12240
12241
12242
12243
12244
12245
12246
12247
12248
12249
12250
12251
12252
12253
12254
12255
12256
12257
12258
12259
12260
12261
12262
12263
12264
12265
12266
12267
12268
12269
12270
12271
12272
12273
12274
12275
  ".cd DIRECTORY            Change the working directory to DIRECTORY",
  ".changes on|off          Show number of rows changed by SQL",
  ".check GLOB              Fail if output since .testcase does not match",
  ".clone NEWDB             Clone data into NEWDB from the existing database",
  ".databases               List names and files of attached databases",
  ".dbconfig ?op? ?val?     List or change sqlite3_db_config() options",
  ".dbinfo ?DB?             Show status information about the database",
  ".dump ?TABLE?            Render database content as SQL",
  "   Options:",
  "     --preserve-rowids      Include ROWID values in the output",
  "     --newlines             Allow unescaped newline characters in output",
  "   TABLE is a LIKE pattern for the tables to dump",
  "   Additional LIKE patterns can be given in subsequent arguments",
  ".echo on|off             Turn command echo on or off",
  ".eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN",
  "   Other Modes:",
#ifdef SQLITE_DEBUG
  "      test                  Show raw EXPLAIN QUERY PLAN output",
  "      trace                 Like \"full\" but enable \"PRAGMA vdbe_trace\"",
#endif
  "      trigger               Like \"full\" but also show trigger bytecode",
  ".excel                   Display the output of next command in spreadsheet",
  "   --bom                   Put a UTF8 byte-order mark on intermediate file",
  ".exit ?CODE?             Exit this program with return-code CODE",
  ".expert                  EXPERIMENTAL. Suggest indexes for queries",
  ".explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto",
  ".filectrl CMD ...        Run various sqlite3_file_control() operations",
  "   --schema SCHEMA         Use SCHEMA instead of \"main\"",
  "   --help                  Show CMD details",
  ".fullschema ?--indent?   Show schema and the content of sqlite_stat tables",
  ".headers on|off          Turn display of headers on or off",
  ".help ?-all? ?PATTERN?   Show help text for PATTERN",
  ".import FILE TABLE       Import data from FILE into TABLE",
  "   Options:",
  "     --ascii               Use \\037 and \\036 as column and row separators",
  "     --csv                 Use , and \\n as column and row separators",
  "     --skip N              Skip the first N rows of input",
  "     -v                    \"Verbose\" - increase auxiliary output",
  "   Notes:",
  "     *  If TABLE does not exist, it is created.  The first row of input",
  "        determines the column names.",
  "     *  If neither --csv or --ascii are used, the input mode is derived",
  "        from the \".mode\" output mode",
  "     *  If FILE begins with \"|\" then it is a command that generates the",
  "        input text.",
#ifndef SQLITE_OMIT_TEST_CONTROL
  ".imposter INDEX TABLE    Create imposter table TABLE on index INDEX",
#endif
  ".indexes ?TABLE?         Show names of indexes",
  "                           If TABLE is specified, only show indexes for",
  "                           tables matching TABLE using the LIKE operator.",
#ifdef SQLITE_ENABLE_IOTRACE
12091
12092
12093
12094
12095
12096
12097
12098
12099
12100
12101
12102



12103
12104
12105
12106
12107
12108
12109
12110
12111
12112
12113
12114
12115
12116




12117
12118
12119
12120
12121
12122
12123
  "     insert   SQL insert statements for TABLE",
  "     line     One value per line",
  "     list     Values delimited by \"|\"",
  "     quote    Escape answers as for SQL",
  "     tabs     Tab-separated values",
  "     tcl      TCL list elements",
  ".nullvalue STRING        Use STRING in place of NULL values",
  ".once (-e|-x|FILE)       Output for the next SQL command only to FILE",
  "     If FILE begins with '|' then open as a pipe",
  "     Other options:",
  "       -e    Invoke system text editor",
  "       -x    Open in a spreadsheet",



  ".open ?OPTIONS? ?FILE?   Close existing database and reopen FILE",
  "     Options:",
  "        --append        Use appendvfs to append database to the end of FILE",
#ifdef SQLITE_ENABLE_DESERIALIZE
  "        --deserialize   Load into memory useing sqlite3_deserialize()",
  "        --hexdb         Load the output of \"dbtotxt\" as an in-memory db",
  "        --maxsize N     Maximum size for --hexdb or --deserialized database",
#endif
  "        --new           Initialize FILE to an empty database",
  "        --nofollow      Do not follow symbolic links",
  "        --readonly      Open FILE readonly",
  "        --zip           FILE is a ZIP archive",
  ".output ?FILE?           Send output to FILE or stdout if FILE is omitted",
  "     If FILE begins with '|' then open it as a pipe.",




  ".parameter CMD ...       Manage SQL parameter bindings",
  "   clear                   Erase all bindings",
  "   init                    Initialize the TEMP table that holds bindings",
  "   list                    List the current parameter bindings",
  "   set PARAMETER VALUE     Given SQL parameter PARAMETER a value of VALUE",
  "                           PARAMETER should start with one of: $ : @ ?",
  "   unset PARAMETER         Remove PARAMETER from the binding table",







|

|
|
|
>
>
>













|
>
>
>
>







12292
12293
12294
12295
12296
12297
12298
12299
12300
12301
12302
12303
12304
12305
12306
12307
12308
12309
12310
12311
12312
12313
12314
12315
12316
12317
12318
12319
12320
12321
12322
12323
12324
12325
12326
12327
12328
12329
12330
12331
  "     insert   SQL insert statements for TABLE",
  "     line     One value per line",
  "     list     Values delimited by \"|\"",
  "     quote    Escape answers as for SQL",
  "     tabs     Tab-separated values",
  "     tcl      TCL list elements",
  ".nullvalue STRING        Use STRING in place of NULL values",
  ".once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE",
  "     If FILE begins with '|' then open as a pipe",
  "       --bom  Put a UTF8 byte-order mark at the beginning",
  "       -e     Send output to the system text editor",
  "       -x     Send output as CSV to a spreadsheet (same as \".excel\")",
#ifdef SQLITE_DEBUG
  ".oom [--repeat M] [N]    Simulate an OOM error on the N-th allocation",
#endif 
  ".open ?OPTIONS? ?FILE?   Close existing database and reopen FILE",
  "     Options:",
  "        --append        Use appendvfs to append database to the end of FILE",
#ifdef SQLITE_ENABLE_DESERIALIZE
  "        --deserialize   Load into memory useing sqlite3_deserialize()",
  "        --hexdb         Load the output of \"dbtotxt\" as an in-memory db",
  "        --maxsize N     Maximum size for --hexdb or --deserialized database",
#endif
  "        --new           Initialize FILE to an empty database",
  "        --nofollow      Do not follow symbolic links",
  "        --readonly      Open FILE readonly",
  "        --zip           FILE is a ZIP archive",
  ".output ?FILE?           Send output to FILE or stdout if FILE is omitted",
  "   If FILE begins with '|' then open it as a pipe.",
  "   Options:",
  "     --bom                 Prefix output with a UTF8 byte-order mark",
  "     -e                    Send output to the system text editor",
  "     -x                    Send output as CSV to a spreadsheet",
  ".parameter CMD ...       Manage SQL parameter bindings",
  "   clear                   Erase all bindings",
  "   init                    Initialize the TEMP table that holds bindings",
  "   list                    List the current parameter bindings",
  "   set PARAMETER VALUE     Given SQL parameter PARAMETER a value of VALUE",
  "                           PARAMETER should start with one of: $ : @ ?",
  "   unset PARAMETER         Remove PARAMETER from the binding table",
12229
12230
12231
12232
12233
12234
12235

12236
12237
12238
12239
12240
12241
12242
  int j = 0;
  int n = 0;
  char *zPat;
  if( zPattern==0
   || zPattern[0]=='0'
   || strcmp(zPattern,"-a")==0
   || strcmp(zPattern,"-all")==0

  ){
    /* Show all commands, but only one line per command */
    if( zPattern==0 ) zPattern = "";
    for(i=0; i<ArraySize(azHelp); i++){
      if( azHelp[i][0]=='.' || zPattern[0] ){
        utf8_printf(out, "%s\n", azHelp[i]);
        n++;







>







12437
12438
12439
12440
12441
12442
12443
12444
12445
12446
12447
12448
12449
12450
12451
  int j = 0;
  int n = 0;
  char *zPat;
  if( zPattern==0
   || zPattern[0]=='0'
   || strcmp(zPattern,"-a")==0
   || strcmp(zPattern,"-all")==0
   || strcmp(zPattern,"--all")==0
  ){
    /* Show all commands, but only one line per command */
    if( zPattern==0 ) zPattern = "";
    for(i=0; i<ArraySize(azHelp); i++){
      if( azHelp[i][0]=='.' || zPattern[0] ){
        utf8_printf(out, "%s\n", azHelp[i]);
        n++;
12710
12711
12712
12713
12714
12715
12716

12717
12718
12719
12720
12721
12722
12723
    }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    sqlite3_enable_load_extension(p->db, 1);
#endif
    sqlite3_fileio_init(p->db, 0, 0);
    sqlite3_shathree_init(p->db, 0, 0);
    sqlite3_completion_init(p->db, 0, 0);

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
    sqlite3_dbdata_init(p->db, 0, 0);
#endif
#ifdef SQLITE_HAVE_ZLIB
    sqlite3_zipfile_init(p->db, 0, 0);
    sqlite3_sqlar_init(p->db, 0, 0);
#endif







>







12919
12920
12921
12922
12923
12924
12925
12926
12927
12928
12929
12930
12931
12932
12933
    }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    sqlite3_enable_load_extension(p->db, 1);
#endif
    sqlite3_fileio_init(p->db, 0, 0);
    sqlite3_shathree_init(p->db, 0, 0);
    sqlite3_completion_init(p->db, 0, 0);
    sqlite3_uint_init(p->db, 0, 0);
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
    sqlite3_dbdata_init(p->db, 0, 0);
#endif
#ifdef SQLITE_HAVE_ZLIB
    sqlite3_zipfile_init(p->db, 0, 0);
    sqlite3_sqlar_init(p->db, 0, 0);
#endif
13046
13047
13048
13049
13050
13051
13052


13053
13054
13055
13056
13057
13058
13059
struct ImportCtx {
  const char *zFile;  /* Name of the input file */
  FILE *in;           /* Read the CSV text from this input stream */
  char *z;            /* Accumulated text for a field */
  int n;              /* Number of bytes in z */
  int nAlloc;         /* Space allocated for z[] */
  int nLine;          /* Current line number */


  int bNotFirst;      /* True if one or more bytes already read */
  int cTerm;          /* Character that terminated the most recent field */
  int cColSep;        /* The column separator character.  (Usually ",") */
  int cRowSep;        /* The row separator character.  (Usually "\n") */
};

/* Append a single byte to z[] */







>
>







13256
13257
13258
13259
13260
13261
13262
13263
13264
13265
13266
13267
13268
13269
13270
13271
struct ImportCtx {
  const char *zFile;  /* Name of the input file */
  FILE *in;           /* Read the CSV text from this input stream */
  char *z;            /* Accumulated text for a field */
  int n;              /* Number of bytes in z */
  int nAlloc;         /* Space allocated for z[] */
  int nLine;          /* Current line number */
  int nRow;           /* Number of rows imported */
  int nErr;           /* Number of errors encountered */
  int bNotFirst;      /* True if one or more bytes already read */
  int cTerm;          /* Character that terminated the most recent field */
  int cColSep;        /* The column separator character.  (Usually ",") */
  int cRowSep;        /* The row separator character.  (Usually "\n") */
};

/* Append a single byte to z[] */
13427
13428
13429
13430
13431
13432
13433





13434
13435
13436
13437
13438
13439
13440
13441
13442
13443
13444
13445
#else
      "xdg-open";
#endif
      char *zCmd;
      zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
      if( system(zCmd) ){
        utf8_printf(stderr, "Failed: [%s]\n", zCmd);





      }
      sqlite3_free(zCmd);
      outputModePop(p);
      p->doXdgOpen = 0;
      sqlite3_sleep(100);
    }
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
  }
  p->outfile[0] = 0;
  p->out = stdout;
}








>
>
>
>
>




<







13639
13640
13641
13642
13643
13644
13645
13646
13647
13648
13649
13650
13651
13652
13653
13654

13655
13656
13657
13658
13659
13660
13661
#else
      "xdg-open";
#endif
      char *zCmd;
      zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
      if( system(zCmd) ){
        utf8_printf(stderr, "Failed: [%s]\n", zCmd);
      }else{
        /* Give the start/open/xdg-open command some time to get
        ** going before we continue, and potential delete the
        ** p->zTempFile data file out from under it */
        sqlite3_sleep(2000);
      }
      sqlite3_free(zCmd);
      outputModePop(p);
      p->doXdgOpen = 0;

    }
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
  }
  p->outfile[0] = 0;
  p->out = stdout;
}

13464
13465
13466
13467
13468
13469
13470
13471
13472
13473
13474
13475
13476
13477
13478
  return (a[0]<<8) + a[1];
}
static unsigned int get4byteInt(unsigned char *a){
  return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
}

/*
** Implementation of the ".info" command.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
  static const struct { const char *zName; int ofst; } aField[] = {
     { "file change counter:",  24  },
     { "database page count:",  28  },







|







13680
13681
13682
13683
13684
13685
13686
13687
13688
13689
13690
13691
13692
13693
13694
  return (a[0]<<8) + a[1];
}
static unsigned int get4byteInt(unsigned char *a){
  return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
}

/*
** Implementation of the ".dbinfo" command.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
  static const struct { const char *zName; int ofst; } aField[] = {
     { "file change counter:",  24  },
     { "database page count:",  28  },
13721
13722
13723
13724
13725
13726
13727



13728
13729









13730
13731
13732
13733
13734
13735
13736
13737
  clearTempFile(p);
  sqlite3_free(p->zTempFile);
  p->zTempFile = 0;
  if( p->db ){
    sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
  }
  if( p->zTempFile==0 ){



    sqlite3_uint64 r;
    sqlite3_randomness(sizeof(r), &r);









    p->zTempFile = sqlite3_mprintf("temp%llx.%s", r, zSuffix);
  }else{
    p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
  }
  if( p->zTempFile==0 ){
    raw_printf(stderr, "out of memory\n");
    exit(1);
  }







>
>
>


>
>
>
>
>
>
>
>
>
|







13937
13938
13939
13940
13941
13942
13943
13944
13945
13946
13947
13948
13949
13950
13951
13952
13953
13954
13955
13956
13957
13958
13959
13960
13961
13962
13963
13964
13965
  clearTempFile(p);
  sqlite3_free(p->zTempFile);
  p->zTempFile = 0;
  if( p->db ){
    sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
  }
  if( p->zTempFile==0 ){
    /* If p->db is an in-memory database then the TEMPFILENAME file-control
    ** will not work and we will need to fallback to guessing */
    char *zTemp;
    sqlite3_uint64 r;
    sqlite3_randomness(sizeof(r), &r);
    zTemp = getenv("TEMP");
    if( zTemp==0 ) zTemp = getenv("TMP");
    if( zTemp==0 ){
#ifdef _WIN32
      zTemp = "\\tmp";
#else
      zTemp = "/tmp";
#endif
    }
    p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
  }else{
    p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
  }
  if( p->zTempFile==0 ){
    raw_printf(stderr, "out of memory\n");
    exit(1);
  }
15701
15702
15703
15704
15705
15706
15707



15708

15709
15710
15711


15712
15713
15714
15715
15716
15717
15718
15719
15720
15721
15722
15723
15724
15725
15726
15727
15728
15729
15730
15731
15732
15733
15734
15735
15736
15737
15738
15739
15740
15741
15742
15743
15744
15745
15746
15747
15748
15749
15750
15751
15752
15753

15754
15755
15756
15757
15758
15759
15760
  }else

  if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){
    static const struct DbConfigChoices {
      const char *zName;
      int op;
    } aDbConfig[] = {



        { "enable_fkey",        SQLITE_DBCONFIG_ENABLE_FKEY           },

        { "enable_trigger",     SQLITE_DBCONFIG_ENABLE_TRIGGER        },
        { "enable_view",        SQLITE_DBCONFIG_ENABLE_VIEW           },
        { "fts3_tokenizer",     SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },


        { "load_extension",     SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
        { "no_ckpt_on_close",   SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE      },
        { "enable_qpsg",        SQLITE_DBCONFIG_ENABLE_QPSG           },
        { "trigger_eqp",        SQLITE_DBCONFIG_TRIGGER_EQP           },
        { "reset_database",     SQLITE_DBCONFIG_RESET_DATABASE        },
        { "defensive",          SQLITE_DBCONFIG_DEFENSIVE             },
        { "writable_schema",    SQLITE_DBCONFIG_WRITABLE_SCHEMA       },
        { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE    },
        { "dqs_dml",            SQLITE_DBCONFIG_DQS_DML               },
        { "dqs_ddl",            SQLITE_DBCONFIG_DQS_DDL               },
        { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    },
    };
    int ii, v;
    open_db(p, 0);
    for(ii=0; ii<ArraySize(aDbConfig); ii++){
      if( nArg>1 && strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
      if( nArg>=3 ){
        sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
      }
      sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
      utf8_printf(p->out, "%18s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
      if( nArg>1 ) break;
    }
    if( nArg>1 && ii==ArraySize(aDbConfig) ){
      utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]);
      utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n");
    }   
  }else

  if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){
    rc = shell_dbinfo_command(p, nArg, azArg);
  }else

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
  if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){
    open_db(p, 0);
    rc = recoverDatabaseCmd(p, nArg, azArg);
  }else
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */

  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
    const char *zLike = 0;

    int i;
    int savedShowHeader = p->showHeader;
    int savedShellFlags = p->shellFlgs;
    ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo);
    for(i=1; i<nArg; i++){
      if( azArg[i][0]=='-' ){
        const char *z = azArg[i]+1;







>
>
>

>



>
>


|

|
<

<
<
<
<









|




















|
>







15929
15930
15931
15932
15933
15934
15935
15936
15937
15938
15939
15940
15941
15942
15943
15944
15945
15946
15947
15948
15949
15950

15951




15952
15953
15954
15955
15956
15957
15958
15959
15960
15961
15962
15963
15964
15965
15966
15967
15968
15969
15970
15971
15972
15973
15974
15975
15976
15977
15978
15979
15980
15981
15982
15983
15984
15985
15986
15987
15988
15989
15990
  }else

  if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){
    static const struct DbConfigChoices {
      const char *zName;
      int op;
    } aDbConfig[] = {
        { "defensive",          SQLITE_DBCONFIG_DEFENSIVE             },
        { "dqs_ddl",            SQLITE_DBCONFIG_DQS_DDL               },
        { "dqs_dml",            SQLITE_DBCONFIG_DQS_DML               },
        { "enable_fkey",        SQLITE_DBCONFIG_ENABLE_FKEY           },
        { "enable_qpsg",        SQLITE_DBCONFIG_ENABLE_QPSG           },
        { "enable_trigger",     SQLITE_DBCONFIG_ENABLE_TRIGGER        },
        { "enable_view",        SQLITE_DBCONFIG_ENABLE_VIEW           },
        { "fts3_tokenizer",     SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
        { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE    },
        { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    },
        { "load_extension",     SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
        { "no_ckpt_on_close",   SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE      },
        { "reset_database",     SQLITE_DBCONFIG_RESET_DATABASE        },
        { "trigger_eqp",        SQLITE_DBCONFIG_TRIGGER_EQP           },
        { "trusted_schema",     SQLITE_DBCONFIG_TRUSTED_SCHEMA        },

        { "writable_schema",    SQLITE_DBCONFIG_WRITABLE_SCHEMA       },




    };
    int ii, v;
    open_db(p, 0);
    for(ii=0; ii<ArraySize(aDbConfig); ii++){
      if( nArg>1 && strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
      if( nArg>=3 ){
        sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
      }
      sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
      utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
      if( nArg>1 ) break;
    }
    if( nArg>1 && ii==ArraySize(aDbConfig) ){
      utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]);
      utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n");
    }   
  }else

  if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){
    rc = shell_dbinfo_command(p, nArg, azArg);
  }else

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
  if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){
    open_db(p, 0);
    rc = recoverDatabaseCmd(p, nArg, azArg);
  }else
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */

  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
    char *zLike = 0;
    char *zSql;
    int i;
    int savedShowHeader = p->showHeader;
    int savedShellFlags = p->shellFlgs;
    ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo);
    for(i=1; i<nArg; i++){
      if( azArg[i][0]=='-' ){
        const char *z = azArg[i]+1;
15774
15775
15776
15777
15778
15779
15780
15781
15782
15783
15784
15785
15786
15787
15788
15789
15790
15791
15792
15793
15794
15795
15796
15797
15798
15799
15800
15801
15802
15803
15804
15805
15806
15807
15808
15809
15810
15811
15812
15813
15814
15815
15816
15817
15818
15819
15820
15821
15822



15823
15824
15825
15826
15827
15828
15829

15830
15831
15832

15833
15834
15835
15836
15837
15838
15839
        }else
        {
          raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
          rc = 1;
          goto meta_command_exit;
        }
      }else if( zLike ){
        raw_printf(stderr, "Usage: .dump ?--preserve-rowids? "
                           "?--newlines? ?LIKE-PATTERN?\n");
        rc = 1;
        goto meta_command_exit;
      }else{
        zLike = azArg[i];
      }
    }

    open_db(p, 0);

    /* When playing back a "dump", the content might appear in an order
    ** which causes immediate foreign key constraints to be violated.
    ** So disable foreign-key constraint enforcement to prevent problems. */
    raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
    raw_printf(p->out, "BEGIN TRANSACTION;\n");
    p->writableSchema = 0;
    p->showHeader = 0;
    /* Set writable_schema=ON since doing so forces SQLite to initialize
    ** as much of the schema as it can even if the sqlite_master table is
    ** corrupt. */
    sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
    p->nErr = 0;
    if( zLike==0 ){
      run_schema_dump_query(p,
        "SELECT name, type, sql FROM sqlite_master "
        "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
      );
      run_schema_dump_query(p,
        "SELECT name, type, sql FROM sqlite_master "
        "WHERE name=='sqlite_sequence'"
      );
      run_table_dump_query(p,
        "SELECT sql FROM sqlite_master "
        "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
      );
    }else{
      char *zSql;
      zSql = sqlite3_mprintf(
        "SELECT name, type, sql FROM sqlite_master "
        "WHERE tbl_name LIKE %Q AND type=='table'"
        "  AND sql NOT NULL", zLike);



      run_schema_dump_query(p,zSql);
      sqlite3_free(zSql);
      zSql = sqlite3_mprintf(
        "SELECT sql FROM sqlite_master "
        "WHERE sql NOT NULL"
        "  AND type IN ('index','trigger','view')"
        "  AND tbl_name LIKE %Q", zLike);

      run_table_dump_query(p, zSql, 0);
      sqlite3_free(zSql);
    }

    if( p->writableSchema ){
      raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
      p->writableSchema = 0;
    }
    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
    sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
    raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");







|
|
<
<

|

















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







16004
16005
16006
16007
16008
16009
16010
16011
16012


16013
16014
16015
16016
16017
16018
16019
16020
16021
16022
16023
16024
16025
16026
16027
16028
16029
16030
16031
16032














16033
16034
16035
16036
16037
16038
16039
16040
16041
16042
16043
16044
16045
16046
16047
16048
16049

16050
16051
16052
16053
16054
16055
16056
16057
        }else
        {
          raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
          rc = 1;
          goto meta_command_exit;
        }
      }else if( zLike ){
        zLike = sqlite3_mprintf("%z OR name LIKE %Q ESCAPE '\\'",
                zLike, azArg[i]);


      }else{
        zLike = sqlite3_mprintf("name LIKE %Q ESCAPE '\\'", azArg[i]);
      }
    }

    open_db(p, 0);

    /* When playing back a "dump", the content might appear in an order
    ** which causes immediate foreign key constraints to be violated.
    ** So disable foreign-key constraint enforcement to prevent problems. */
    raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
    raw_printf(p->out, "BEGIN TRANSACTION;\n");
    p->writableSchema = 0;
    p->showHeader = 0;
    /* Set writable_schema=ON since doing so forces SQLite to initialize
    ** as much of the schema as it can even if the sqlite_master table is
    ** corrupt. */
    sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
    p->nErr = 0;
    if( zLike==0 ) zLike = sqlite3_mprintf("true");














    zSql = sqlite3_mprintf(
      "SELECT name, type, sql FROM sqlite_master "
      "WHERE (%s) AND type=='table'"
      "  AND sql NOT NULL"
      " ORDER BY tbl_name='sqlite_sequence', rowid",
      zLike
    );
    run_schema_dump_query(p,zSql);
    sqlite3_free(zSql);
    zSql = sqlite3_mprintf(
      "SELECT sql FROM sqlite_master "
      "WHERE (%s) AND sql NOT NULL"
      "  AND type IN ('index','trigger','view')",
      zLike
    );
    run_table_dump_query(p, zSql);
    sqlite3_free(zSql);

    sqlite3_free(zLike);
    if( p->writableSchema ){
      raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
      p->writableSchema = 0;
    }
    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
    sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
    raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
15928
15929
15930
15931
15932
15933
15934

15935
15936
15937
15938
15939
15940
15941

15942
15943
15944










15945
15946
15947
15948
15949
15950
15951
   /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY,  "COUNT DELAY"    },*/
      { "persist_wal",    SQLITE_FCNTL_PERSIST_WAL,     "[BOOLEAN]"      },
      { "psow",       SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]"      },
   /* { "pragma",         SQLITE_FCNTL_PRAGMA,          "NAME ARG"       },*/
      { "tempfilename",   SQLITE_FCNTL_TEMPFILENAME,    ""               },
      { "has_moved",      SQLITE_FCNTL_HAS_MOVED,       ""               },  
      { "lock_timeout",   SQLITE_FCNTL_LOCK_TIMEOUT,    "MILLISEC"       },

    };
    int filectrl = -1;
    int iCtrl = -1;
    sqlite3_int64 iRes = 0;  /* Integer result to display if rc2==1 */
    int isOk = 0;            /* 0: usage  1: %lld  2: no-result */
    int n2, i;
    const char *zCmd = 0;


    open_db(p, 0);
    zCmd = nArg>=2 ? azArg[1] : "help";











    /* The argument can optionally begin with "-" or "--" */
    if( zCmd[0]=='-' && zCmd[1] ){
      zCmd++;
      if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
    }








>







>



>
>
>
>
>
>
>
>
>
>







16146
16147
16148
16149
16150
16151
16152
16153
16154
16155
16156
16157
16158
16159
16160
16161
16162
16163
16164
16165
16166
16167
16168
16169
16170
16171
16172
16173
16174
16175
16176
16177
16178
16179
16180
16181
   /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY,  "COUNT DELAY"    },*/
      { "persist_wal",    SQLITE_FCNTL_PERSIST_WAL,     "[BOOLEAN]"      },
      { "psow",       SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]"      },
   /* { "pragma",         SQLITE_FCNTL_PRAGMA,          "NAME ARG"       },*/
      { "tempfilename",   SQLITE_FCNTL_TEMPFILENAME,    ""               },
      { "has_moved",      SQLITE_FCNTL_HAS_MOVED,       ""               },  
      { "lock_timeout",   SQLITE_FCNTL_LOCK_TIMEOUT,    "MILLISEC"       },
      { "reserve_bytes",  SQLITE_FCNTL_RESERVE_BYTES,   "[N]"            },
    };
    int filectrl = -1;
    int iCtrl = -1;
    sqlite3_int64 iRes = 0;  /* Integer result to display if rc2==1 */
    int isOk = 0;            /* 0: usage  1: %lld  2: no-result */
    int n2, i;
    const char *zCmd = 0;
    const char *zSchema = 0;

    open_db(p, 0);
    zCmd = nArg>=2 ? azArg[1] : "help";

    if( zCmd[0]=='-' 
     && (strcmp(zCmd,"--schema")==0 || strcmp(zCmd,"-schema")==0)
     && nArg>=4
    ){
      zSchema = azArg[2];
      for(i=3; i<nArg; i++) azArg[i-2] = azArg[i];
      nArg -= 2;
      zCmd = azArg[1];
    }

    /* The argument can optionally begin with "-" or "--" */
    if( zCmd[0]=='-' && zCmd[1] ){
      zCmd++;
      if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
    }

15980
15981
15982
15983
15984
15985
15986
15987
15988
15989
15990
15991
15992
15993
15994
15995
15996
15997
15998
15999
16000
16001
16002
16003
16004
16005
16006
16007
16008
16009
16010
16011
16012
16013
16014
16015
16016
16017
16018
16019
16020
16021
16022
16023
16024
16025
16026
16027












16028
16029
16030
16031
16032
16033
16034
      utf8_printf(stderr,"Error: unknown file-control: %s\n"
                         "Use \".filectrl --help\" for help\n", zCmd);
    }else{
      switch(filectrl){
        case SQLITE_FCNTL_SIZE_LIMIT: {
          if( nArg!=2 && nArg!=3 ) break;
          iRes = nArg==3 ? integerValue(azArg[2]) : -1;
          sqlite3_file_control(p->db, 0, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
          isOk = 1;
          break;
        }
        case SQLITE_FCNTL_LOCK_TIMEOUT:
        case SQLITE_FCNTL_CHUNK_SIZE: {
          int x;
          if( nArg!=3 ) break;
          x = (int)integerValue(azArg[2]);
          sqlite3_file_control(p->db, 0, filectrl, &x);
          isOk = 2;
          break;
        }
        case SQLITE_FCNTL_PERSIST_WAL:
        case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
          int x;
          if( nArg!=2 && nArg!=3 ) break;
          x = nArg==3 ? booleanValue(azArg[2]) : -1;
          sqlite3_file_control(p->db, 0, filectrl, &x);
          iRes = x;
          isOk = 1;
          break;
        }
        case SQLITE_FCNTL_HAS_MOVED: {
          int x;
          if( nArg!=2 ) break;
          sqlite3_file_control(p->db, 0, filectrl, &x);
          iRes = x;
          isOk = 1;
          break;
        }
        case SQLITE_FCNTL_TEMPFILENAME: {
          char *z = 0;
          if( nArg!=2 ) break;
          sqlite3_file_control(p->db, 0, filectrl, &z);
          if( z ){
            utf8_printf(p->out, "%s\n", z);
            sqlite3_free(z);
          }
          isOk = 2;
          break;












        }
      }
    }
    if( isOk==0 && iCtrl>=0 ){
      utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
      rc = 1;
    }else if( isOk==1 ){







|








|








|







|







|






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







16210
16211
16212
16213
16214
16215
16216
16217
16218
16219
16220
16221
16222
16223
16224
16225
16226
16227
16228
16229
16230
16231
16232
16233
16234
16235
16236
16237
16238
16239
16240
16241
16242
16243
16244
16245
16246
16247
16248
16249
16250
16251
16252
16253
16254
16255
16256
16257
16258
16259
16260
16261
16262
16263
16264
16265
16266
16267
16268
16269
16270
16271
16272
16273
16274
16275
16276
      utf8_printf(stderr,"Error: unknown file-control: %s\n"
                         "Use \".filectrl --help\" for help\n", zCmd);
    }else{
      switch(filectrl){
        case SQLITE_FCNTL_SIZE_LIMIT: {
          if( nArg!=2 && nArg!=3 ) break;
          iRes = nArg==3 ? integerValue(azArg[2]) : -1;
          sqlite3_file_control(p->db, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
          isOk = 1;
          break;
        }
        case SQLITE_FCNTL_LOCK_TIMEOUT:
        case SQLITE_FCNTL_CHUNK_SIZE: {
          int x;
          if( nArg!=3 ) break;
          x = (int)integerValue(azArg[2]);
          sqlite3_file_control(p->db, zSchema, filectrl, &x);
          isOk = 2;
          break;
        }
        case SQLITE_FCNTL_PERSIST_WAL:
        case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
          int x;
          if( nArg!=2 && nArg!=3 ) break;
          x = nArg==3 ? booleanValue(azArg[2]) : -1;
          sqlite3_file_control(p->db, zSchema, filectrl, &x);
          iRes = x;
          isOk = 1;
          break;
        }
        case SQLITE_FCNTL_HAS_MOVED: {
          int x;
          if( nArg!=2 ) break;
          sqlite3_file_control(p->db, zSchema, filectrl, &x);
          iRes = x;
          isOk = 1;
          break;
        }
        case SQLITE_FCNTL_TEMPFILENAME: {
          char *z = 0;
          if( nArg!=2 ) break;
          sqlite3_file_control(p->db, zSchema, filectrl, &z);
          if( z ){
            utf8_printf(p->out, "%s\n", z);
            sqlite3_free(z);
          }
          isOk = 2;
          break;
        }
        case SQLITE_FCNTL_RESERVE_BYTES: {
          int x;
          if( nArg>=3 ){
            x = atoi(azArg[2]);
            sqlite3_file_control(p->db, zSchema, filectrl, &x);
          }
          x = -1;
          sqlite3_file_control(p->db, zSchema, filectrl, &x);
          utf8_printf(p->out,"%d\n", x);
          isOk = 2;
          break;
        }
      }
    }
    if( isOk==0 && iCtrl>=0 ){
      utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
      rc = 1;
    }else if( isOk==1 ){
16105
16106
16107
16108
16109
16110
16111
16112
16113
16114
16115
16116
16117
16118
16119
16120
16121
16122
16123
16124
16125
16126
16127
16128
16129
16130
16131
16132


16133



16134


16135




16136
16137
16138

16139
16140














16141
16142








16143

16144



















16145
16146

16147
16148

16149
16150
16151
16152
16153
16154
16155
16156
16157
16158
16159
16160
16161




16162
16163
16164
16165
16166
16167
16168

16169
16170
16171
16172
16173
16174
16175
16176
16177
16178
16179
16180
16181
16182
16183
16184
16185

16186



16187



16188







16189
16190
16191
16192
16193
16194
16195
      }
    }else{
      showHelp(p->out, 0);
    }
  }else

  if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
    char *zTable;               /* Insert data into this table */
    char *zFile;                /* Name of file to extra content from */
    sqlite3_stmt *pStmt = NULL; /* A statement */
    int nCol;                   /* Number of columns in the table */
    int nByte;                  /* Number of bytes in an SQL string */
    int i, j;                   /* Loop counters */
    int needCommit;             /* True to COMMIT or ROLLBACK at end */
    int nSep;                   /* Number of bytes in p->colSeparator[] */
    char *zSql;                 /* An SQL statement */
    ImportCtx sCtx;             /* Reader context */
    char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
    int (SQLITE_CDECL *xCloser)(FILE*);      /* Func to close file */

    if( nArg!=3 ){
      raw_printf(stderr, "Usage: .import FILE TABLE\n");
      goto meta_command_exit;
    }
    zFile = azArg[1];
    zTable = azArg[2];
    seenInterrupt = 0;
    memset(&sCtx, 0, sizeof(sCtx));


    open_db(p, 0);



    nSep = strlen30(p->colSeparator);


    if( nSep==0 ){




      raw_printf(stderr,
                 "Error: non-null column separator required for import\n");
      return 1;

    }
    if( nSep>1 ){














      raw_printf(stderr, "Error: multi-character column separators not allowed"
                      " for import\n");








      return 1;

    }



















    nSep = strlen30(p->rowSeparator);
    if( nSep==0 ){

      raw_printf(stderr, "Error: non-null row separator required for import\n");
      return 1;

    }
    if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
      /* When importing CSV (only), if the row separator is set to the
      ** default output row separator, change it to the default input
      ** row separator.  This avoids having to maintain different input
      ** and output row separators. */
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
      nSep = strlen30(p->rowSeparator);
    }
    if( nSep>1 ){
      raw_printf(stderr, "Error: multi-character row separators not allowed"
                      " for import\n");
      return 1;




    }
    sCtx.zFile = zFile;
    sCtx.nLine = 1;
    if( sCtx.zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      return 1;

#else
      sCtx.in = popen(sCtx.zFile+1, "r");
      sCtx.zFile = "<pipe>";
      xCloser = pclose;
#endif
    }else{
      sCtx.in = fopen(sCtx.zFile, "rb");
      xCloser = fclose;
    }
    if( p->mode==MODE_Ascii ){
      xRead = ascii_read_one_field;
    }else{
      xRead = csv_read_one_field;
    }
    if( sCtx.in==0 ){
      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
      return 1;

    }



    sCtx.cColSep = p->colSeparator[0];



    sCtx.cRowSep = p->rowSeparator[0];







    zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
    if( zSql==0 ){
      xCloser(sCtx.in);
      shell_out_of_memory();
    }
    nByte = strlen30(zSql);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);







|
|










|
|
|
<
|
<
<
<

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

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






|
>









<
<
<
<
<


|
>

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







16347
16348
16349
16350
16351
16352
16353
16354
16355
16356
16357
16358
16359
16360
16361
16362
16363
16364
16365
16366
16367
16368

16369



16370
16371
16372
16373
16374
16375
16376
16377
16378
16379
16380
16381
16382
16383
16384
16385
16386
16387
16388
16389
16390
16391
16392
16393
16394
16395
16396
16397
16398
16399
16400
16401
16402
16403
16404
16405
16406
16407
16408
16409
16410
16411
16412
16413
16414
16415
16416
16417
16418
16419
16420
16421
16422
16423
16424
16425
16426
16427
16428
16429
16430
16431
16432
16433
16434
16435
16436
16437
16438
16439
16440
16441
16442
16443
16444
16445
16446
16447
16448
16449
16450
16451
16452
16453
16454
16455
16456
16457
16458
16459
16460
16461
16462
16463
16464
16465
16466
16467
16468
16469
16470
16471
16472
16473
16474
16475
16476





16477
16478
16479
16480
16481
16482
16483
16484
16485
16486
16487
16488
16489
16490
16491
16492
16493
16494
16495
16496
16497
16498
16499
16500
16501
16502
16503
      }
    }else{
      showHelp(p->out, 0);
    }
  }else

  if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
    char *zTable = 0;           /* Insert data into this table */
    char *zFile = 0;            /* Name of file to extra content from */
    sqlite3_stmt *pStmt = NULL; /* A statement */
    int nCol;                   /* Number of columns in the table */
    int nByte;                  /* Number of bytes in an SQL string */
    int i, j;                   /* Loop counters */
    int needCommit;             /* True to COMMIT or ROLLBACK at end */
    int nSep;                   /* Number of bytes in p->colSeparator[] */
    char *zSql;                 /* An SQL statement */
    ImportCtx sCtx;             /* Reader context */
    char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
    int (SQLITE_CDECL *xCloser)(FILE*);      /* Func to close file */
    int eVerbose = 0;           /* Larger for more console output */
    int nSkip = 0;              /* Initial lines to skip */
    int useOutputMode = 1;      /* Use output mode to determine separators */





    memset(&sCtx, 0, sizeof(sCtx));
    if( p->mode==MODE_Ascii ){
      xRead = ascii_read_one_field;
    }else{
      xRead = csv_read_one_field;
    }
    for(i=1; i<nArg; i++){
      char *z = azArg[i];
      if( z[0]=='-' && z[1]=='-' ) z++;
      if( z[0]!='-' ){
        if( zFile==0 ){
          zFile = z;
        }else if( zTable==0 ){
          zTable = z;
        }else{
          utf8_printf(p->out, "ERROR: extra argument: \"%s\".  Usage:\n", z);
          showHelp(p->out, "import");
          rc = 1;
          goto meta_command_exit;
        }
      }else if( strcmp(z,"-v")==0 ){
        eVerbose++;
      }else if( strcmp(z,"-skip")==0 && i<nArg-1 ){
        nSkip = integerValue(azArg[++i]);
      }else if( strcmp(z,"-ascii")==0 ){
        sCtx.cColSep = SEP_Unit[0];
        sCtx.cRowSep = SEP_Record[0];
        xRead = ascii_read_one_field;
        useOutputMode = 0;
      }else if( strcmp(z,"-csv")==0 ){
        sCtx.cColSep = ',';
        sCtx.cRowSep = '\n';
        xRead = csv_read_one_field;
        useOutputMode = 0;
      }else{
        utf8_printf(p->out, "ERROR: unknown option: \"%s\".  Usage:\n", z);
        showHelp(p->out, "import");
        rc = 1;
        goto meta_command_exit;
      }
    }
    if( zTable==0 ){
      utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n",
                  zFile==0 ? "FILE" : "TABLE");
      showHelp(p->out, "import");
      rc = 1;
      goto meta_command_exit;
    }
    seenInterrupt = 0;
    open_db(p, 0);
    if( useOutputMode ){
      /* If neither the --csv or --ascii options are specified, then set
      ** the column and row separator characters from the output mode. */
      nSep = strlen30(p->colSeparator);
      if( nSep==0 ){
        raw_printf(stderr,
                   "Error: non-null column separator required for import\n");
        rc = 1;
        goto meta_command_exit;
      }
      if( nSep>1 ){
        raw_printf(stderr, 
              "Error: multi-character column separators not allowed"
              " for import\n");
        rc = 1;
        goto meta_command_exit;
      }
      nSep = strlen30(p->rowSeparator);
      if( nSep==0 ){
        raw_printf(stderr,
            "Error: non-null row separator required for import\n");
        rc = 1;
        goto meta_command_exit;
      }
      if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){
        /* When importing CSV (only), if the row separator is set to the
        ** default output row separator, change it to the default input
        ** row separator.  This avoids having to maintain different input
        ** and output row separators. */
        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
        nSep = strlen30(p->rowSeparator);
      }
      if( nSep>1 ){
        raw_printf(stderr, "Error: multi-character row separators not allowed"
                           " for import\n");
        rc = 1;
        goto meta_command_exit;
      }
      sCtx.cColSep = p->colSeparator[0];
      sCtx.cRowSep = p->rowSeparator[0];
    }
    sCtx.zFile = zFile;
    sCtx.nLine = 1;
    if( sCtx.zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      rc = 1;
      goto meta_command_exit;
#else
      sCtx.in = popen(sCtx.zFile+1, "r");
      sCtx.zFile = "<pipe>";
      xCloser = pclose;
#endif
    }else{
      sCtx.in = fopen(sCtx.zFile, "rb");
      xCloser = fclose;
    }





    if( sCtx.in==0 ){
      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
      rc = 1;
      goto meta_command_exit;
    }
    if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
      char zSep[2];
      zSep[1] = 0;
      zSep[0] = sCtx.cColSep;
      utf8_printf(p->out, "Column separator ");
      output_c_string(p->out, zSep);
      utf8_printf(p->out, ", row separator ");
      zSep[0] = sCtx.cRowSep;
      output_c_string(p->out, zSep);
      utf8_printf(p->out, "\n");
    }
    while( (nSkip--)>0 ){
      while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
      sCtx.nLine++;
    }
    zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
    if( zSql==0 ){
      xCloser(sCtx.in);
      shell_out_of_memory();
    }
    nByte = strlen30(zSql);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
16203
16204
16205
16206
16207
16208
16209
16210

16211
16212



16213
16214
16215
16216
16217
16218
16219
16220

16221
16222
16223
16224
16225
16226
16227
16228
16229

16230
16231
16232
16233
16234
16235
16236
16237
16238
16239
16240
16241
16242
16243
16244
16245
16246
16247



16248
16249
16250
16251
16252
16253
16254

16255
16256
16257
16258
16259
16260
16261
        if( sCtx.cTerm!=sCtx.cColSep ) break;
      }
      if( cSep=='(' ){
        sqlite3_free(zCreate);
        sqlite3_free(sCtx.z);
        xCloser(sCtx.in);
        utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
        return 1;

      }
      zCreate = sqlite3_mprintf("%z\n)", zCreate);



      rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
      sqlite3_free(zCreate);
      if( rc ){
        utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
                sqlite3_errmsg(p->db));
        sqlite3_free(sCtx.z);
        xCloser(sCtx.in);
        return 1;

      }
      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    }
    sqlite3_free(zSql);
    if( rc ){
      if (pStmt) sqlite3_finalize(pStmt);
      utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
      xCloser(sCtx.in);
      return 1;

    }
    nCol = sqlite3_column_count(pStmt);
    sqlite3_finalize(pStmt);
    pStmt = 0;
    if( nCol==0 ) return 0; /* no columns, no error */
    zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
    if( zSql==0 ){
      xCloser(sCtx.in);
      shell_out_of_memory();
    }
    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
    j = strlen30(zSql);
    for(i=1; i<nCol; i++){
      zSql[j++] = ',';
      zSql[j++] = '?';
    }
    zSql[j++] = ')';
    zSql[j] = 0;



    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    if( rc ){
      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
      if (pStmt) sqlite3_finalize(pStmt);
      xCloser(sCtx.in);
      return 1;

    }
    needCommit = sqlite3_get_autocommit(p->db);
    if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
    do{
      int startLine = sCtx.nLine;
      for(i=0; i<nCol; i++){
        char *z = xRead(&sCtx);







|
>


>
>
>







|
>








|
>


















>
>
>






|
>







16511
16512
16513
16514
16515
16516
16517
16518
16519
16520
16521
16522
16523
16524
16525
16526
16527
16528
16529
16530
16531
16532
16533
16534
16535
16536
16537
16538
16539
16540
16541
16542
16543
16544
16545
16546
16547
16548
16549
16550
16551
16552
16553
16554
16555
16556
16557
16558
16559
16560
16561
16562
16563
16564
16565
16566
16567
16568
16569
16570
16571
16572
16573
16574
16575
16576
16577
16578
16579
        if( sCtx.cTerm!=sCtx.cColSep ) break;
      }
      if( cSep=='(' ){
        sqlite3_free(zCreate);
        sqlite3_free(sCtx.z);
        xCloser(sCtx.in);
        utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
        rc = 1;
        goto meta_command_exit;
      }
      zCreate = sqlite3_mprintf("%z\n)", zCreate);
      if( eVerbose>=1 ){
        utf8_printf(p->out, "%s\n", zCreate);
      }
      rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
      sqlite3_free(zCreate);
      if( rc ){
        utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
                sqlite3_errmsg(p->db));
        sqlite3_free(sCtx.z);
        xCloser(sCtx.in);
        rc = 1;
        goto meta_command_exit;
      }
      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    }
    sqlite3_free(zSql);
    if( rc ){
      if (pStmt) sqlite3_finalize(pStmt);
      utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
      xCloser(sCtx.in);
      rc = 1;
      goto meta_command_exit;
    }
    nCol = sqlite3_column_count(pStmt);
    sqlite3_finalize(pStmt);
    pStmt = 0;
    if( nCol==0 ) return 0; /* no columns, no error */
    zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
    if( zSql==0 ){
      xCloser(sCtx.in);
      shell_out_of_memory();
    }
    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
    j = strlen30(zSql);
    for(i=1; i<nCol; i++){
      zSql[j++] = ',';
      zSql[j++] = '?';
    }
    zSql[j++] = ')';
    zSql[j] = 0;
    if( eVerbose>=2 ){
      utf8_printf(p->out, "Insert using: %s\n", zSql);
    }
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    if( rc ){
      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
      if (pStmt) sqlite3_finalize(pStmt);
      xCloser(sCtx.in);
      rc = 1;
      goto meta_command_exit;
    }
    needCommit = sqlite3_get_autocommit(p->db);
    if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
    do{
      int startLine = sCtx.nLine;
      for(i=0; i<nCol; i++){
        char *z = xRead(&sCtx);
16290
16291
16292
16293
16294
16295
16296



16297
16298
16299
16300
16301
16302
16303
16304





16305
16306
16307
16308
16309
16310
16311
      }
      if( i>=nCol ){
        sqlite3_step(pStmt);
        rc = sqlite3_reset(pStmt);
        if( rc!=SQLITE_OK ){
          utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
                      startLine, sqlite3_errmsg(p->db));



        }
      }
    }while( sCtx.cTerm!=EOF );

    xCloser(sCtx.in);
    sqlite3_free(sCtx.z);
    sqlite3_finalize(pStmt);
    if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);





  }else

#ifndef SQLITE_UNTESTABLE
  if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
    char *zSql;
    char *zCollist = 0;
    sqlite3_stmt *pStmt;







>
>
>








>
>
>
>
>







16608
16609
16610
16611
16612
16613
16614
16615
16616
16617
16618
16619
16620
16621
16622
16623
16624
16625
16626
16627
16628
16629
16630
16631
16632
16633
16634
16635
16636
16637
      }
      if( i>=nCol ){
        sqlite3_step(pStmt);
        rc = sqlite3_reset(pStmt);
        if( rc!=SQLITE_OK ){
          utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
                      startLine, sqlite3_errmsg(p->db));
          sCtx.nErr++;
        }else{
          sCtx.nRow++;
        }
      }
    }while( sCtx.cTerm!=EOF );

    xCloser(sCtx.in);
    sqlite3_free(sCtx.z);
    sqlite3_finalize(pStmt);
    if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
    if( eVerbose>0 ){
      utf8_printf(p->out,
          "Added %d rows with %d errors using %d lines of input\n",
          sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
    }
  }else

#ifndef SQLITE_UNTESTABLE
  if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
    char *zSql;
    char *zCollist = 0;
    sqlite3_stmt *pStmt;
16576
16577
16578
16579
16580
16581
16582




























16583
16584
16585
16586
16587
16588
16589
                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .nullvalue STRING\n");
      rc = 1;
    }
  }else





























  if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
    char *zNewFilename;  /* Name of the database file to open */
    int iName = 1;       /* Index in azArg[] of the filename */
    int newFlag = 0;     /* True to delete file before opening */
    /* Close the existing database */
    session_close_all(p);
    close_db(p->db);







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







16902
16903
16904
16905
16906
16907
16908
16909
16910
16911
16912
16913
16914
16915
16916
16917
16918
16919
16920
16921
16922
16923
16924
16925
16926
16927
16928
16929
16930
16931
16932
16933
16934
16935
16936
16937
16938
16939
16940
16941
16942
16943
                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .nullvalue STRING\n");
      rc = 1;
    }
  }else

#ifdef SQLITE_DEBUG
  if( c=='o' && strcmp(azArg[0],"oom")==0 ){
    int i;
    for(i=1; i<nArg; i++){
      const char *z = azArg[i];
      if( z[0]=='-' && z[1]=='-' ) z++;
      if( strcmp(z,"-repeat")==0 ){
        if( i==nArg-1 ){
          raw_printf(p->out, "missing argument on \"%s\"\n", azArg[i]);
          rc = 1;
        }else{
          oomRepeat = (int)integerValue(azArg[++i]);
        }
      }else if( IsDigit(z[0]) ){
        oomCounter = (int)integerValue(azArg[i]);
      }else{
        raw_printf(p->out, "unknown argument: \"%s\"\n", azArg[i]);
        raw_printf(p->out, "Usage: .oom [--repeat N] [M]\n");
        rc = 1;
      }
    }
    if( rc==0 ){
      raw_printf(p->out, "oomCounter = %d\n", oomCounter);
      raw_printf(p->out, "oomRepeat  = %d\n", oomRepeat);
    }
  }else
#endif /* SQLITE_DEBUG */

  if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
    char *zNewFilename;  /* Name of the database file to open */
    int iName = 1;       /* Index in azArg[] of the filename */
    int newFlag = 0;     /* True to delete file before opening */
    /* Close the existing database */
    session_close_all(p);
    close_db(p->db);
16643
16644
16645
16646
16647
16648
16649
16650
16651





16652
16653

16654
16655
16656
16657
16658


16659










16660
16661
16662
16663
16664



16665
16666

16667
16668
16669



16670
16671
16672
16673
16674
16675
16676
16677

16678
16679
16680

16681

16682
16683
16684
16685

16686
16687
16688
16689
16690
16691
16692
16693
16694
16695
16696
16697
16698
16699
16700
16701
16702
16703

16704
16705
16706
16707
16708
16709
16710
16711
16712
16713
16714
16715

16716
16717
16718
16719
16720
16721
16722
    }
  }else

  if( (c=='o'
        && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
   || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
  ){
    const char *zFile = nArg>=2 ? azArg[1] : "stdout";
    int bTxtMode = 0;





    if( azArg[0][0]=='e' ){
      /* Transform the ".excel" command into ".once -x" */

      nArg = 2;
      azArg[0] = "once";
      zFile = azArg[1] = "-x";
      n = 4;
    }


    if( nArg>2 ){










      utf8_printf(stderr, "Usage: .%s [-e|-x|FILE]\n", azArg[0]);
      rc = 1;
      goto meta_command_exit;
    }
    if( n>1 && strncmp(azArg[0], "once", n)==0 ){



      if( nArg<2 ){
        raw_printf(stderr, "Usage: .once (-e|-x|FILE)\n");

        rc = 1;
        goto meta_command_exit;
      }



      p->outCount = 2;
    }else{
      p->outCount = 0;
    }
    output_reset(p);
    if( zFile[0]=='-' && zFile[1]=='-' ) zFile++;
#ifndef SQLITE_NOHAVE_SYSTEM
    if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){

      p->doXdgOpen = 1;
      outputModePush(p);
      if( zFile[1]=='x' ){

        newTempFile(p, "csv");

        p->mode = MODE_Csv;
        sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
      }else{

        newTempFile(p, "txt");
        bTxtMode = 1;
      }
      zFile = p->zTempFile;
    }
#endif /* SQLITE_NOHAVE_SYSTEM */
    if( zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      rc = 1;
      p->out = stdout;
#else
      p->out = popen(zFile + 1, "w");
      if( p->out==0 ){
        utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
        p->out = stdout;
        rc = 1;
      }else{

        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
      }
#endif
    }else{
      p->out = output_file_open(zFile, bTxtMode);
      if( p->out==0 ){
        if( strcmp(zFile,"off")!=0 ){
          utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
        }
        p->out = stdout;
        rc = 1;
      } else {

        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
      }
    }
  }else

  if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){
    open_db(p,0);







|

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

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



>
>
>





<

<
>


|
>

>




>


















>












>







16997
16998
16999
17000
17001
17002
17003
17004
17005
17006
17007
17008
17009
17010
17011

17012
17013
17014

17015
17016
17017
17018
17019
17020
17021
17022
17023
17024
17025
17026
17027
17028
17029
17030
17031
17032
17033
17034
17035
17036
17037
17038

17039
17040
17041
17042
17043
17044
17045
17046
17047
17048
17049
17050

17051

17052
17053
17054
17055
17056
17057
17058
17059
17060
17061
17062
17063
17064
17065
17066
17067
17068
17069
17070
17071
17072
17073
17074
17075
17076
17077
17078
17079
17080
17081
17082
17083
17084
17085
17086
17087
17088
17089
17090
17091
17092
17093
17094
17095
17096
17097
17098
17099
17100
17101
17102
    }
  }else

  if( (c=='o'
        && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
   || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
  ){
    const char *zFile = 0;
    int bTxtMode = 0;
    int i;
    int eMode = 0;
    int bBOM = 0;
    int bOnce;

    if( c=='e' ){

      eMode = 'x';
      bOnce = 2;
    }else if( strncmp(azArg[0],"once",n)==0 ){

      bOnce = 1;
    }
    for(i=1; i<nArg; i++){
      char *z = azArg[i];
      if( z[0]=='-' ){
        if( z[1]=='-' ) z++;
        if( strcmp(z,"-bom")==0 ){
          bBOM = 1;
        }else if( c!='e' && strcmp(z,"-x")==0 ){
          eMode = 'x';  /* spreadsheet */
        }else if( c!='e' && strcmp(z,"-e")==0 ){
          eMode = 'e';  /* text editor */
        }else{
          utf8_printf(p->out, "ERROR: unknown option: \"%s\".  Usage:\n",
                      azArg[i]);
          showHelp(p->out, azArg[0]);
          rc = 1;
          goto meta_command_exit;
        }
      }else if( zFile==0 ){
        zFile = z;
      }else{
        utf8_printf(p->out,"ERROR: extra parameter: \"%s\".  Usage:\n",
                    azArg[i]);

        showHelp(p->out, azArg[0]);
        rc = 1;
        goto meta_command_exit;
      }
    }
    if( zFile==0 ) zFile = "stdout";
    if( bOnce ){
      p->outCount = 2;
    }else{
      p->outCount = 0;
    }
    output_reset(p);

#ifndef SQLITE_NOHAVE_SYSTEM

    if( eMode=='e' || eMode=='x' ){
      p->doXdgOpen = 1;
      outputModePush(p);
      if( eMode=='x' ){
        /* spreadsheet mode.  Output as CSV. */
        newTempFile(p, "csv");
        ShellClearFlag(p, SHFLG_Echo);
        p->mode = MODE_Csv;
        sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
      }else{
        /* text editor mode */
        newTempFile(p, "txt");
        bTxtMode = 1;
      }
      zFile = p->zTempFile;
    }
#endif /* SQLITE_NOHAVE_SYSTEM */
    if( zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      rc = 1;
      p->out = stdout;
#else
      p->out = popen(zFile + 1, "w");
      if( p->out==0 ){
        utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
        p->out = stdout;
        rc = 1;
      }else{
        if( bBOM ) fprintf(p->out,"\357\273\277");
        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
      }
#endif
    }else{
      p->out = output_file_open(zFile, bTxtMode);
      if( p->out==0 ){
        if( strcmp(zFile,"off")!=0 ){
          utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
        }
        p->out = stdout;
        rc = 1;
      } else {
        if( bBOM ) fprintf(p->out,"\357\273\277");
        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
      }
    }
  }else

  if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){
    open_db(p,0);
17761
17762
17763
17764
17765
17766
17767
17768
17769
17770
17771
17772
17773
17774
17775
17776
17777
17778
17779
17780
17781
17782
17783
17784
17785
17786
      { "assert",             SQLITE_TESTCTRL_ASSERT,        "BOOLEAN"        },
    /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, ""       },*/
    /*{ "bitvec_test",        SQLITE_TESTCTRL_BITVEC_TEST,   ""             },*/
      { "byteorder",          SQLITE_TESTCTRL_BYTEORDER,     ""               },
      { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,"BOOLEAN"   },
    /*{ "fault_install",      SQLITE_TESTCTRL_FAULT_INSTALL, ""             },*/
      { "imposter",         SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"},
      { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "BOOLEAN"   },
      { "localtime_fault",    SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN"       },
      { "never_corrupt",      SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN"        },
      { "optimizations",      SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK"   },
#ifdef YYCOVERAGE
      { "parser_coverage",    SQLITE_TESTCTRL_PARSER_COVERAGE, ""             },
#endif
      { "pending_byte",       SQLITE_TESTCTRL_PENDING_BYTE,  "OFFSET  "       },
      { "prng_restore",       SQLITE_TESTCTRL_PRNG_RESTORE,  ""               },
      { "prng_save",          SQLITE_TESTCTRL_PRNG_SAVE,     ""               },
      { "prng_seed",          SQLITE_TESTCTRL_PRNG_SEED,     "SEED ?db?"      },
      { "reserve",            SQLITE_TESTCTRL_RESERVE,      "BYTES-OF-RESERVE"},
    };
    int testctrl = -1;
    int iCtrl = -1;
    int rc2 = 0;    /* 0: usage.  1: %d  2: %x  3: no-output */
    int isOk = 0;
    int i, n2;
    const char *zCmd = 0;







|










<







18141
18142
18143
18144
18145
18146
18147
18148
18149
18150
18151
18152
18153
18154
18155
18156
18157
18158

18159
18160
18161
18162
18163
18164
18165
      { "assert",             SQLITE_TESTCTRL_ASSERT,        "BOOLEAN"        },
    /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, ""       },*/
    /*{ "bitvec_test",        SQLITE_TESTCTRL_BITVEC_TEST,   ""             },*/
      { "byteorder",          SQLITE_TESTCTRL_BYTEORDER,     ""               },
      { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,"BOOLEAN"   },
    /*{ "fault_install",      SQLITE_TESTCTRL_FAULT_INSTALL, ""             },*/
      { "imposter",         SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"},
      { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "" },
      { "localtime_fault",    SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN"       },
      { "never_corrupt",      SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN"        },
      { "optimizations",      SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK"   },
#ifdef YYCOVERAGE
      { "parser_coverage",    SQLITE_TESTCTRL_PARSER_COVERAGE, ""             },
#endif
      { "pending_byte",       SQLITE_TESTCTRL_PENDING_BYTE,  "OFFSET  "       },
      { "prng_restore",       SQLITE_TESTCTRL_PRNG_RESTORE,  ""               },
      { "prng_save",          SQLITE_TESTCTRL_PRNG_SAVE,     ""               },
      { "prng_seed",          SQLITE_TESTCTRL_PRNG_SEED,     "SEED ?db?"      },

    };
    int testctrl = -1;
    int iCtrl = -1;
    int rc2 = 0;    /* 0: usage.  1: %d  2: %x  3: no-output */
    int isOk = 0;
    int i, n2;
    const char *zCmd = 0;
17825
17826
17827
17828
17829
17830
17831
17832
17833
17834
17835
17836
17837
17838
17839
      utf8_printf(stderr,"Error: unknown test-control: %s\n"
                         "Use \".testctrl --help\" for help\n", zCmd);
    }else{
      switch(testctrl){

        /* sqlite3_test_control(int, db, int) */
        case SQLITE_TESTCTRL_OPTIMIZATIONS:
        case SQLITE_TESTCTRL_RESERVE:
          if( nArg==3 ){
            int opt = (int)strtol(azArg[2], 0, 0);
            rc2 = sqlite3_test_control(testctrl, p->db, opt);
            isOk = 3;
          }
          break;








<







18204
18205
18206
18207
18208
18209
18210

18211
18212
18213
18214
18215
18216
18217
      utf8_printf(stderr,"Error: unknown test-control: %s\n"
                         "Use \".testctrl --help\" for help\n", zCmd);
    }else{
      switch(testctrl){

        /* sqlite3_test_control(int, db, int) */
        case SQLITE_TESTCTRL_OPTIMIZATIONS:

          if( nArg==3 ){
            int opt = (int)strtol(azArg[2], 0, 0);
            rc2 = sqlite3_test_control(testctrl, p->db, opt);
            isOk = 3;
          }
          break;

17877
17878
17879
17880
17881
17882
17883
17884
17885
17886
17887
17888
17889
17890
17891
17892
17893
17894
17895
17896
17897
17898
17899
17900






17901
17902
17903
17904
17905
17906
17907
            isOk = 3;
          }
          break;

        /* sqlite3_test_control(int, int) */
        case SQLITE_TESTCTRL_ASSERT:
        case SQLITE_TESTCTRL_ALWAYS:
        case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
          if( nArg==3 ){
            int opt = booleanValue(azArg[2]);
            rc2 = sqlite3_test_control(testctrl, opt);
            isOk = 1;
          }
          break;

        /* sqlite3_test_control(int, int) */
        case SQLITE_TESTCTRL_LOCALTIME_FAULT:
        case SQLITE_TESTCTRL_NEVER_CORRUPT:
          if( nArg==3 ){
            int opt = booleanValue(azArg[2]);
            rc2 = sqlite3_test_control(testctrl, opt);
            isOk = 3;
          }
          break;







        case SQLITE_TESTCTRL_IMPOSTER:
          if( nArg==5 ){
            rc2 = sqlite3_test_control(testctrl, p->db,
                          azArg[2],
                          integerValue(azArg[3]),
                          integerValue(azArg[4]));







<
















>
>
>
>
>
>







18255
18256
18257
18258
18259
18260
18261

18262
18263
18264
18265
18266
18267
18268
18269
18270
18271
18272
18273
18274
18275
18276
18277
18278
18279
18280
18281
18282
18283
18284
18285
18286
18287
18288
18289
18290
            isOk = 3;
          }
          break;

        /* sqlite3_test_control(int, int) */
        case SQLITE_TESTCTRL_ASSERT:
        case SQLITE_TESTCTRL_ALWAYS:

          if( nArg==3 ){
            int opt = booleanValue(azArg[2]);
            rc2 = sqlite3_test_control(testctrl, opt);
            isOk = 1;
          }
          break;

        /* sqlite3_test_control(int, int) */
        case SQLITE_TESTCTRL_LOCALTIME_FAULT:
        case SQLITE_TESTCTRL_NEVER_CORRUPT:
          if( nArg==3 ){
            int opt = booleanValue(azArg[2]);
            rc2 = sqlite3_test_control(testctrl, opt);
            isOk = 3;
          }
          break;

        /* sqlite3_test_control(sqlite3*) */
        case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
          rc2 = sqlite3_test_control(testctrl, p->db);
          isOk = 3;
          break;

        case SQLITE_TESTCTRL_IMPOSTER:
          if( nArg==5 ){
            rc2 = sqlite3_test_control(testctrl, p->db,
                          azArg[2],
                          integerValue(azArg[3]),
                          integerValue(azArg[4]));
18592
18593
18594
18595
18596
18597
18598

18599
18600
18601
18602
18603
18604

18605

18606

18607
18608
18609
18610
18611
18612
18613
}

/*
** Output text to the console in a font that attracts extra attention.
*/
#ifdef _WIN32
static void printBold(const char *zText){

  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
  CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
  GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
  SetConsoleTextAttribute(out,
         FOREGROUND_RED|FOREGROUND_INTENSITY
  );

  printf("%s", zText);

  SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);

}
#else
static void printBold(const char *zText){
  printf("\033[1m%s\033[0m", zText);
}
#endif








>






>

>

>







18975
18976
18977
18978
18979
18980
18981
18982
18983
18984
18985
18986
18987
18988
18989
18990
18991
18992
18993
18994
18995
18996
18997
18998
18999
19000
}

/*
** Output text to the console in a font that attracts extra attention.
*/
#ifdef _WIN32
static void printBold(const char *zText){
#if !SQLITE_OS_WINRT
  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
  CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
  GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
  SetConsoleTextAttribute(out,
         FOREGROUND_RED|FOREGROUND_INTENSITY
  );
#endif
  printf("%s", zText);
#if !SQLITE_OS_WINRT
  SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
#endif
}
#else
static void printBold(const char *zText){
  printf("\033[1m%s\033[0m", zText);
}
#endif

18653
18654
18655
18656
18657
18658
18659




18660
18661
18662
18663
18664
18665
18666
18667
18668
18669



18670

18671
18672
18673
18674
18675
18676
18677
  int argcToFree = 0;
#endif

  setBinaryMode(stdin, 0);
  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
  stdin_is_interactive = isatty(0);
  stdout_is_console = isatty(1);





#if !defined(_WIN32_WCE)
  if( getenv("SQLITE_DEBUG_BREAK") ){
    if( isatty(0) && isatty(2) ){
      fprintf(stderr,
          "attach debugger to process %d and press any key to continue.\n",
          GETPID());
      fgetc(stdin);
    }else{
#if defined(_WIN32) || defined(WIN32)



      DebugBreak();

#elif defined(SIGTRAP)
      raise(SIGTRAP);
#endif
    }
  }
#endif








>
>
>
>










>
>
>

>







19040
19041
19042
19043
19044
19045
19046
19047
19048
19049
19050
19051
19052
19053
19054
19055
19056
19057
19058
19059
19060
19061
19062
19063
19064
19065
19066
19067
19068
19069
19070
19071
19072
  int argcToFree = 0;
#endif

  setBinaryMode(stdin, 0);
  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
  stdin_is_interactive = isatty(0);
  stdout_is_console = isatty(1);

#ifdef SQLITE_DEBUG
  registerOomSimulator();
#endif

#if !defined(_WIN32_WCE)
  if( getenv("SQLITE_DEBUG_BREAK") ){
    if( isatty(0) && isatty(2) ){
      fprintf(stderr,
          "attach debugger to process %d and press any key to continue.\n",
          GETPID());
      fgetc(stdin);
    }else{
#if defined(_WIN32) || defined(WIN32)
#if SQLITE_OS_WINRT
      __debugbreak();
#else
      DebugBreak();
#endif
#elif defined(SIGTRAP)
      raise(SIGTRAP);
#endif
    }
  }
#endif

Changes to src/smtp.c.
596
597
598
599
600
601
602

603
604
605
606
607
608
609
610
611

612
613
614
615
616
617
618
619
620

621
622
623
624
625
626
627




628

629
630
631
632
633
634
635
**
** Use SMTP to send the email message contained in the file named EMAIL
** to the list of users TO.  FROM is the sender of the email.
**
** Options:
**
**      --direct              Go directly to the TO domain.  Bypass MX lookup

**      --port N              Use TCP port N instead of 25
**      --trace               Show the SMTP conversation on the console
*/
void test_smtp_send(void){
  SmtpSession *p;
  const char *zFrom;
  int nTo;
  const char *zToDomain;
  const char *zFromDomain;

  const char **azTo;
  int smtpPort = 25;
  const char *zPort;
  Blob body;
  u32 smtpFlags = SMTP_PORT;
  if( find_option("trace",0,0)!=0 ) smtpFlags |= SMTP_TRACE_STDOUT;
  if( find_option("direct",0,0)!=0 ) smtpFlags |= SMTP_DIRECT;
  zPort = find_option("port",0,1);
  if( zPort ) smtpPort = atoi(zPort);

  verify_all_options();
  if( g.argc<5 ) usage("EMAIL FROM TO ...");
  blob_read_from_file(&body, g.argv[2], ExtFILE);
  zFrom = g.argv[3];
  nTo = g.argc-4;
  azTo = (const char**)g.argv+4;
  zFromDomain = domainOfAddr(zFrom);




  zToDomain = domainOfAddr(azTo[0]);

  p = smtp_session_new(zFromDomain, zToDomain, smtpFlags, smtpPort);
  if( p->zErr ){
    fossil_fatal("%s", p->zErr);
  }
  fossil_print("Connection to \"%s\"\n", p->zHostname);
  smtp_client_startup(p);
  smtp_send_msg(p, zFrom, nTo, azTo, blob_str(&body));







>









>









>







>
>
>
>
|
>







596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
**
** Use SMTP to send the email message contained in the file named EMAIL
** to the list of users TO.  FROM is the sender of the email.
**
** Options:
**
**      --direct              Go directly to the TO domain.  Bypass MX lookup
**      --relayhost R         Use R as relay host directly for delivery.
**      --port N              Use TCP port N instead of 25
**      --trace               Show the SMTP conversation on the console
*/
void test_smtp_send(void){
  SmtpSession *p;
  const char *zFrom;
  int nTo;
  const char *zToDomain;
  const char *zFromDomain;
  const char *zRelay;
  const char **azTo;
  int smtpPort = 25;
  const char *zPort;
  Blob body;
  u32 smtpFlags = SMTP_PORT;
  if( find_option("trace",0,0)!=0 ) smtpFlags |= SMTP_TRACE_STDOUT;
  if( find_option("direct",0,0)!=0 ) smtpFlags |= SMTP_DIRECT;
  zPort = find_option("port",0,1);
  if( zPort ) smtpPort = atoi(zPort);
  zRelay = find_option("relayhost",0,1);
  verify_all_options();
  if( g.argc<5 ) usage("EMAIL FROM TO ...");
  blob_read_from_file(&body, g.argv[2], ExtFILE);
  zFrom = g.argv[3];
  nTo = g.argc-4;
  azTo = (const char**)g.argv+4;
  zFromDomain = domainOfAddr(zFrom);
  if( zRelay!=0 && zRelay[0]!= 0) {
    smtpFlags |= SMTP_DIRECT;
    zToDomain = zRelay;
  }else{
    zToDomain = domainOfAddr(azTo[0]);
  }
  p = smtp_session_new(zFromDomain, zToDomain, smtpFlags, smtpPort);
  if( p->zErr ){
    fossil_fatal("%s", p->zErr);
  }
  fossil_print("Connection to \"%s\"\n", p->zHostname);
  smtp_client_startup(p);
  smtp_send_msg(p, zFrom, nTo, azTo, blob_str(&body));
Added src/sounds/0.wav.

cannot compute difference between binary files

Added src/sounds/1.wav.

cannot compute difference between binary files

Added src/sounds/2.wav.

cannot compute difference between binary files

Added src/sounds/3.wav.

cannot compute difference between binary files

Added src/sounds/4.wav.

cannot compute difference between binary files

Added src/sounds/5.wav.

cannot compute difference between binary files

Added src/sounds/6.wav.

cannot compute difference between binary files

Added src/sounds/7.wav.

cannot compute difference between binary files

Added src/sounds/8.wav.

cannot compute difference between binary files

Added src/sounds/9.wav.

cannot compute difference between binary files

Added src/sounds/README.md.


























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
The *.wav files in this directory contain a human voice speaking each
of the 16 hexadecimal digits.  If a captcha string consists of just
hexadecimal digits (as is the case for captchas generated by the
[../captcha.c module](../captcha.c)) then these WAV files can be
concatenated together to generate an audio reading of the captcha, which
enables visually impaired users to complete the captcha.

Each of the WAV files uses 8000 samples per second, 8 bytes per sample
and are 6000 samples in length.

The recordings are made by Philip Bennefall and are of his own voice.
Mr. Bennefall is himself blind and uses this system implemented with these
recordings to complete captchas for Fossil.
Added src/sounds/a.wav.

cannot compute difference between binary files

Added src/sounds/b.wav.

cannot compute difference between binary files

Added src/sounds/c.wav.

cannot compute difference between binary files

Added src/sounds/d.wav.

cannot compute difference between binary files

Added src/sounds/e.wav.

cannot compute difference between binary files

Added src/sounds/f.wav.

cannot compute difference between binary files

Changes to src/sqlcmd.c.
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
    sqlite3_free(pOut);
    sqlite3_result_error_nomem(context);
  }else{
    sqlite3_free(pOut);
    sqlite3_result_error(context, "input is not zlib compressed", -1);
  }
}














/*
** Add the content(), compress(), and decompress() SQL functions to
** database connection db.
*/
int add_content_sql_commands(sqlite3 *db){
  sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
                          sqlcmd_content, 0, 0);
  sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
                          sqlcmd_compress, 0, 0);
  sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
                          sqlcmd_decompress, 0, 0);


  return SQLITE_OK;
}

/*
** This is the "automatic extension" initializer that runs right after
** the connection to the repository database is opened.  Set up the
** database connection to be more useful to the human operator.







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












>
>







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
    sqlite3_free(pOut);
    sqlite3_result_error_nomem(context);
  }else{
    sqlite3_free(pOut);
    sqlite3_result_error(context, "input is not zlib compressed", -1);
  }
}

/*
** Implementation of the "gather_artifact_stats(X)" SQL function.
** That function merely calls the gather_artifact_stats() function
** in stat.c to populate the ARTSTAT temporary table.
*/
static void sqlcmd_gather_artifact_stats(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  gather_artifact_stats(1);
}

/*
** Add the content(), compress(), and decompress() SQL functions to
** database connection db.
*/
int add_content_sql_commands(sqlite3 *db){
  sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
                          sqlcmd_content, 0, 0);
  sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
                          sqlcmd_compress, 0, 0);
  sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
                          sqlcmd_decompress, 0, 0);
  sqlite3_create_function(db, "gather_artifact_stats", 0, SQLITE_UTF8, 0,
                          sqlcmd_gather_artifact_stats, 0, 0);
  return SQLITE_OK;
}

/*
** This is the "automatic extension" initializer that runs right after
** the connection to the repository database is opened.  Set up the
** database connection to be more useful to the human operator.
Changes to src/sqlite3.c.
1
2
3
4
5
6
7
8
9
10
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.31.0.  By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit.  This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately.  Performance improvements
** of 5% or more are commonly seen when SQLite is compiled as a single
** translation unit.
**
** This file is all you need to compile SQLite.  To use SQLite in other


|







1
2
3
4
5
6
7
8
9
10
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.32.0.  By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit.  This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately.  Performance improvements
** of 5% or more are commonly seen when SQLite is compiled as a single
** translation unit.
**
** This file is all you need to compile SQLite.  To use SQLite in other
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
#endif
#if SQLITE_FTS5_ENABLE_TEST_MI
  "FTS5_ENABLE_TEST_MI",
#endif
#if SQLITE_FTS5_NO_WITHOUT_ROWID
  "FTS5_NO_WITHOUT_ROWID",
#endif
#if SQLITE_HAS_CODEC
  "HAS_CODEC",
#endif
#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
  "HAVE_ISNAN",
#endif
#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
  "HOMEGROWN_RECURSIVE_MUTEX",
#endif
#if SQLITE_IGNORE_AFP_LOCK_ERRORS







<
<
<







376
377
378
379
380
381
382



383
384
385
386
387
388
389
#endif
#if SQLITE_FTS5_ENABLE_TEST_MI
  "FTS5_ENABLE_TEST_MI",
#endif
#if SQLITE_FTS5_NO_WITHOUT_ROWID
  "FTS5_NO_WITHOUT_ROWID",
#endif



#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
  "HAVE_ISNAN",
#endif
#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
  "HOMEGROWN_RECURSIVE_MUTEX",
#endif
#if SQLITE_IGNORE_AFP_LOCK_ERRORS
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
** been edited in any way since it was last checked in, then the last
** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.31.0"
#define SQLITE_VERSION_NUMBER 3031000
#define SQLITE_SOURCE_ID      "2019-11-20 13:31:52 a0f6d526baecd061a5e2bec5eb698fb5dfb10122ac79c853d7b3f4a48bc9f49b"

/*
** 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







|
|
|







1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
** been edited in any way since it was last checked in, then the last
** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.32.0"
#define SQLITE_VERSION_NUMBER 3032000
#define SQLITE_SOURCE_ID      "2020-04-20 17:35:32 2fc80ef16ce5878311ab88a0c64631813572ffbb71f75363b4619c9667e0926b"

/*
** 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
1574
1575
1576
1577
1578
1579
1580

1581
1582
1583
1584
1585

1586
1587
1588
1589
1590
1591
1592
#define SQLITE_CONSTRAINT_FUNCTION     (SQLITE_CONSTRAINT | (4<<8))
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))

#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))


/*
** CAPI3REF: Flags For File Open Operations
**
** These bit values are intended for use in the
** 3rd parameter to the [sqlite3_open_v2()] interface and
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.







>





>







1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
#define SQLITE_CONSTRAINT_FUNCTION     (SQLITE_CONSTRAINT | (4<<8))
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))
#define SQLITE_CONSTRAINT_PINNED       (SQLITE_CONSTRAINT |(11<<8))
#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK              (SQLITE_OK | (2<<8))

/*
** CAPI3REF: Flags For File Open Operations
**
** These bit values are intended for use in the
** 3rd parameter to the [sqlite3_open_v2()] interface and
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
** file control occurs at the beginning of pragma statement analysis and so
** it is able to override built-in [PRAGMA] statements.
**
** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
** to the connections busy-handler callback. The argument is of type (void **)
** - an array of two (void *) values. The first (void *) actually points
** to a function of type (int (*)(void *)). In order to invoke the connections
** busy-handler, this function should be invoked with the second (void *) in
** the array as the only argument. If it returns non-zero, then the operation
** should be retried. If it returns zero, the custom VFS should abandon the
** current operation.
**
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses.  The
** argument should be a char** which will be filled with the filename
** written into memory obtained from [sqlite3_malloc()].  The caller should
** invoke [sqlite3_free()] on the result to avoid a memory leak.
**







|

|






|







2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
** file control occurs at the beginning of pragma statement analysis and so
** it is able to override built-in [PRAGMA] statements.
**
** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
** to the connection's busy-handler callback. The argument is of type (void**)
** - an array of two (void *) values. The first (void *) actually points
** to a function of type (int (*)(void *)). In order to invoke the connection's
** busy-handler, this function should be invoked with the second (void *) in
** the array as the only argument. If it returns non-zero, then the operation
** should be retried. If it returns zero, the custom VFS should abandon the
** current operation.
**
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
** ^Applications can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses.  The
** argument should be a char** which will be filled with the filename
** written into memory obtained from [sqlite3_malloc()].  The caller should
** invoke [sqlite3_free()] on the result to avoid a memory leak.
**
2123
2124
2125
2126
2127
2128
2129
2130

2131
2132
2133


2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153






2154
2155
2156
2157
2158
2159
2160
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
** ^This file control takes the file descriptor out of batch write mode
** so that all subsequent write operations are independent.
** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
**
** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain

** a file lock using the xLock or xShmLock methods of the VFS to wait
** for up to M milliseconds before failing, where M is the single 
** unsigned integer parameter.


**
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
** a database file.  The argument is a pointer to a 32-bit unsigned integer.
** The "data version" for the pager is written into the pointer.  The
** "data version" changes whenever any change occurs to the corresponding
** database file, either through SQL statements on the same database
** connection or through transactions committed by separate database
** connections possibly in other processes. The [sqlite3_total_changes()]
** interface can be used to find if any database on the connection has changed,
** but that interface responds to changes on TEMP as well as MAIN and does
** not provide a mechanism to detect changes to MAIN only.  Also, the
** [sqlite3_total_changes()] interface responds to internal changes only and
** omits changes made by other database connections.  The
** [PRAGMA data_version] command provide a mechanism to detect changes to
** a single attached database that occur due to other database connections,
** but omits changes implemented by the database connection on which it is
** called.  This file control is the only mechanism to detect changes that
** happen either internally or externally and that are associated with
** a particular attached database.






** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE               1
#define SQLITE_FCNTL_GET_LOCKPROXYFILE       2
#define SQLITE_FCNTL_SET_LOCKPROXYFILE       3
#define SQLITE_FCNTL_LAST_ERRNO              4
#define SQLITE_FCNTL_SIZE_HINT               5







|
>
|
<
|
>
>














|





>
>
>
>
>
>







2122
2123
2124
2125
2126
2127
2128
2129
2130
2131

2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
** ^This file control takes the file descriptor out of batch write mode
** so that all subsequent write operations are independent.
** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
**
** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS
** to block for up to M milliseconds before failing when attempting to 
** obtain a file lock using the xLock or xShmLock methods of the VFS. 

** The parameter is a pointer to a 32-bit signed integer that contains
** the value that M is to be set to. Before returning, the 32-bit signed
** integer is overwritten with the previous value of M.
**
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
** a database file.  The argument is a pointer to a 32-bit unsigned integer.
** The "data version" for the pager is written into the pointer.  The
** "data version" changes whenever any change occurs to the corresponding
** database file, either through SQL statements on the same database
** connection or through transactions committed by separate database
** connections possibly in other processes. The [sqlite3_total_changes()]
** interface can be used to find if any database on the connection has changed,
** but that interface responds to changes on TEMP as well as MAIN and does
** not provide a mechanism to detect changes to MAIN only.  Also, the
** [sqlite3_total_changes()] interface responds to internal changes only and
** omits changes made by other database connections.  The
** [PRAGMA data_version] command provides a mechanism to detect changes to
** a single attached database that occur due to other database connections,
** but omits changes implemented by the database connection on which it is
** called.  This file control is the only mechanism to detect changes that
** happen either internally or externally and that are associated with
** a particular attached database.
**
** <li>[[SQLITE_FCNTL_CKPT_DONE]]
** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
** in wal mode after the client has finished copying pages from the wal
** file to the database file, but before the *-shm file is updated to
** record the fact that the pages have been checkpointed.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE               1
#define SQLITE_FCNTL_GET_LOCKPROXYFILE       2
#define SQLITE_FCNTL_SET_LOCKPROXYFILE       3
#define SQLITE_FCNTL_LAST_ERRNO              4
#define SQLITE_FCNTL_SIZE_HINT               5
2184
2185
2186
2187
2188
2189
2190


2191
2192
2193
2194
2195
2196
2197
#define SQLITE_FCNTL_PDB                    30
#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
#define SQLITE_FCNTL_LOCK_TIMEOUT           34
#define SQLITE_FCNTL_DATA_VERSION           35
#define SQLITE_FCNTL_SIZE_LIMIT             36



/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
#define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
#define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO









>
>







2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
#define SQLITE_FCNTL_PDB                    30
#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
#define SQLITE_FCNTL_LOCK_TIMEOUT           34
#define SQLITE_FCNTL_DATA_VERSION           35
#define SQLITE_FCNTL_SIZE_LIMIT             36
#define SQLITE_FCNTL_CKPT_DONE              37
#define SQLITE_FCNTL_RESERVE_BYTES          38

/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
#define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
#define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO


2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
** the end.  Each time such an extension occurs, the iVersion field
** is incremented.  The iVersion value started out as 1 in
** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6].  Additional fields
** may be appended to the sqlite3_vfs object and the iVersion value
** may increase again in future versions of SQLite.
** Note that the structure
** of the sqlite3_vfs object changes in the transition from
** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
** and yet the iVersion field was not modified.
**
** The szOsFile field is the size of the subclassed [sqlite3_file]
** structure used by this VFS.  mxPathname is the maximum length of
** a pathname in this VFS.
**
** Registered sqlite3_vfs objects are kept on a linked list formed by
** the pNext pointer.  The [sqlite3_vfs_register()]







|
|

|







2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
** the end.  Each time such an extension occurs, the iVersion field
** is incremented.  The iVersion value started out as 1 in
** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6].  Additional fields
** may be appended to the sqlite3_vfs object and the iVersion value
** may increase again in future versions of SQLite.
** Note that due to an oversight, the structure
** of the sqlite3_vfs object changed in the transition from
** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
** and yet the iVersion field was not increased.
**
** The szOsFile field is the size of the subclassed [sqlite3_file]
** structure used by this VFS.  mxPathname is the maximum length of
** a pathname in this VFS.
**
** Registered sqlite3_vfs objects are kept on a linked list formed by
** the pNext pointer.  The [sqlite3_vfs_register()]
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
** API.  The SQLITE_OPEN_EXCLUSIVE flag, when paired with the 
** SQLITE_OPEN_CREATE, is used to indicate that file should always
** be created, and that it is an error if it already exists.
** It is <i>not</i> used to indicate the file should be opened 
** for exclusive access.
**
** ^At least szOsFile bytes of memory are allocated by SQLite
** to hold the  [sqlite3_file] structure passed as the third
** argument to xOpen.  The xOpen method does not have to
** allocate the structure; it should just fill it in.  Note that
** the xOpen method must set the sqlite3_file.pMethods to either
** a valid [sqlite3_io_methods] object or to NULL.  xOpen must do
** this even if the open fails.  SQLite expects that the sqlite3_file.pMethods
** element will be valid after xOpen returns regardless of the success
** or failure of the xOpen call.







|







2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
** API.  The SQLITE_OPEN_EXCLUSIVE flag, when paired with the 
** SQLITE_OPEN_CREATE, is used to indicate that file should always
** be created, and that it is an error if it already exists.
** It is <i>not</i> used to indicate the file should be opened 
** for exclusive access.
**
** ^At least szOsFile bytes of memory are allocated by SQLite
** to hold the [sqlite3_file] structure passed as the third
** argument to xOpen.  The xOpen method does not have to
** allocate the structure; it should just fill it in.  Note that
** the xOpen method must set the sqlite3_file.pMethods to either
** a valid [sqlite3_io_methods] object or to NULL.  xOpen must do
** this even if the open fails.  SQLite expects that the sqlite3_file.pMethods
** element will be valid after xOpen returns regardless of the success
** or failure of the xOpen call.
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
** checks whether the file is readable.  The SQLITE_ACCESS_READ constant is
** currently unused, though it might be used in a future release of
** SQLite.
*/
#define SQLITE_ACCESS_EXISTS    0
#define SQLITE_ACCESS_READWRITE 1   /* Used by PRAGMA temp_store_directory */
#define SQLITE_ACCESS_READ      2   /* Unused */
#define SQLITE_ACCESS_SYMLINK   3   /* Test if file is symbolic link */

/*
** CAPI3REF: Flags for the xShmLock VFS method
**
** These integer constants define the various locking operations
** allowed by the xShmLock method of [sqlite3_io_methods].  The
** following are the only legal combinations of flags to the







<







2455
2456
2457
2458
2459
2460
2461

2462
2463
2464
2465
2466
2467
2468
** checks whether the file is readable.  The SQLITE_ACCESS_READ constant is
** currently unused, though it might be used in a future release of
** SQLite.
*/
#define SQLITE_ACCESS_EXISTS    0
#define SQLITE_ACCESS_READWRITE 1   /* Used by PRAGMA temp_store_directory */
#define SQLITE_ACCESS_READ      2   /* Unused */


/*
** CAPI3REF: Flags for the xShmLock VFS method
**
** These integer constants define the various locking operations
** allowed by the xShmLock method of [sqlite3_io_methods].  The
** following are the only legal combinations of flags to the
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
** allocators round up memory allocations at least to the next multiple
** of 8.  Some allocators round up to a larger multiple or to a power of 2.
** Every memory allocation request coming in through [sqlite3_malloc()]
** or [sqlite3_realloc()] first calls xRoundup.  If xRoundup returns 0, 
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator.  For example,
** it might allocate any require mutexes or initialize internal data
** structures.  The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
** by xInit.  The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe.  The







|







2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
** allocators round up memory allocations at least to the next multiple
** of 8.  Some allocators round up to a larger multiple or to a power of 2.
** Every memory allocation request coming in through [sqlite3_malloc()]
** or [sqlite3_realloc()] first calls xRoundup.  If xRoundup returns 0, 
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator.  For example,
** it might allocate any required mutexes or initialize internal data
** structures.  The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
** by xInit.  The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe.  The
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
** that SQLite can use for the database page cache with the default page
** cache implementation.  
** This configuration option is a no-op if an application-define page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned memory (pMem), the size of each page cache line (sz),
** and the number of cache lines (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 65536) plus some extra bytes for each
** page header.  ^The number of extra bytes needed by the page header







|







2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
** that SQLite can use for the database page cache with the default page
** cache implementation.  
** This configuration option is a no-op if an application-defined page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned memory (pMem), the size of each page cache line (sz),
** and the number of cache lines (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 65536) plus some extra bytes for each
** page header.  ^The number of extra bytes needed by the page header
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307





















3308
3309
3310
3311
3312
3313
3314
** additional information. This feature can also be turned on and off
** using the [PRAGMA legacy_alter_table] statement.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
** <dt>SQLITE_DBCONFIG_DQS_DML</td>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statement
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>





















**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag.  When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
** integer found at offset 44 into the database header) of 1.  This in turn







|













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







3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
** additional information. This feature can also be turned on and off
** using the [PRAGMA legacy_alter_table] statement.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
** <dt>SQLITE_DBCONFIG_DQS_DML</td>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas (the contents of the [sqlite_master] tables)
** are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
** takes additional defensive steps to protect the application from harm
** including:
** <ul>
** <li> Prohibit the use of SQL functions inside triggers, views,
** CHECK constraints, DEFAULT clauses, expression indexes, 
** partial indexes, or generated columns
** unless those functions are tagged with [SQLITE_INNOCUOUS].
** <li> Prohibit the use of virtual tables inside of triggers or views
** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS].
** </ul>
** This setting defaults to "on" for legacy compatibility, however
** all applications are advised to turn it off if possible. This setting
** can also be controlled using the [PRAGMA trusted_schema] statement.
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag.  When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
** integer found at offset 44 into the database header) of 1.  This in turn
3342
3343
3344
3345
3346
3347
3348

3349
3350
3351
3352
3353
3354
3355
3356
#define SQLITE_DBCONFIG_DEFENSIVE             1010 /* int int* */
#define SQLITE_DBCONFIG_WRITABLE_SCHEMA       1011 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE    1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML               1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL               1014 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_VIEW           1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    1016 /* int int* */

#define SQLITE_DBCONFIG_MAX                   1016 /* Largest DBCONFIG */

/*
** CAPI3REF: Enable Or Disable Extended Result Codes
** METHOD: sqlite3
**
** ^The sqlite3_extended_result_codes() routine enables or disables the
** [extended result codes] feature of SQLite. ^The extended result







>
|







3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
#define SQLITE_DBCONFIG_DEFENSIVE             1010 /* int int* */
#define SQLITE_DBCONFIG_WRITABLE_SCHEMA       1011 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE    1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML               1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL               1014 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_VIEW           1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA        1017 /* int int* */
#define SQLITE_DBCONFIG_MAX                   1017 /* Largest DBCONFIG */

/*
** CAPI3REF: Enable Or Disable Extended Result Codes
** METHOD: sqlite3
**
** ^The sqlite3_extended_result_codes() routine enables or disables the
** [extended result codes] feature of SQLite. ^The extended result
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE
** that is inside an explicit transaction, then the entire transaction
** will be rolled back automatically.
**
** ^The sqlite3_interrupt(D) call is in effect until all currently running
** SQL statements on [database connection] D complete.  ^Any new SQL statements
** that are started after the sqlite3_interrupt() call and before the 
** running statements reaches zero are interrupted as if they had been
** running prior to the sqlite3_interrupt() call.  ^New SQL statements
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
*/







|







3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE
** that is inside an explicit transaction, then the entire transaction
** will be rolled back automatically.
**
** ^The sqlite3_interrupt(D) call is in effect until all currently running
** SQL statements on [database connection] D complete.  ^Any new SQL statements
** that are started after the sqlite3_interrupt() call and before the 
** running statement count reaches zero are interrupted as if they had been
** running prior to the sqlite3_interrupt() call.  ^New SQL statements
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
*/
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
**        Name        | Age
**        -----------------------
**        Alice       | 43
**        Bob         | 28
**        Cindy       | 21
** </pre></blockquote>
**
** There are two column (M==2) and three rows (N==3).  Thus the
** result table has 8 entries.  Suppose the result table is stored
** in an array names azResult.  Then azResult holds this content:
**
** <blockquote><pre>
**        azResult&#91;0] = "Name";
**        azResult&#91;1] = "Age";
**        azResult&#91;2] = "Alice";
**        azResult&#91;3] = "43";
**        azResult&#91;4] = "Bob";







|

|







3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
**        Name        | Age
**        -----------------------
**        Alice       | 43
**        Bob         | 28
**        Cindy       | 21
** </pre></blockquote>
**
** There are two columns (M==2) and three rows (N==3).  Thus the
** result table has 8 entries.  Suppose the result table is stored
** in an array named azResult.  Then azResult holds this content:
**
** <blockquote><pre>
**        azResult&#91;0] = "Name";
**        azResult&#91;1] = "Age";
**        azResult&#91;2] = "Alice";
**        azResult&#91;3] = "43";
**        azResult&#91;4] = "Bob";
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);

/*
** CAPI3REF: Memory Allocation Subsystem
**
** The SQLite core uses these three routines for all of its own
** internal memory allocation needs. "Core" in the previous sentence
** does not include operating-system specific VFS implementation.  The
** Windows VFS uses native malloc() and free() for some operations.
**
** ^The sqlite3_malloc() routine returns a pointer to a block
** of memory at least N bytes in length, where N is the parameter.
** ^If sqlite3_malloc() is unable to obtain sufficient free
** memory, it returns a NULL pointer.  ^If the parameter N to
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns







|







3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);

/*
** CAPI3REF: Memory Allocation Subsystem
**
** The SQLite core uses these three routines for all of its own
** internal memory allocation needs. "Core" in the previous sentence
** does not include operating-system specific [VFS] implementation.  The
** Windows VFS uses native malloc() and free() for some operations.
**
** ^The sqlite3_malloc() routine returns a pointer to a block
** of memory at least N bytes in length, where N is the parameter.
** ^If sqlite3_malloc() is unable to obtain sufficient free
** memory, it returns a NULL pointer.  ^If the parameter N to
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
**
** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
** sqlite3_malloc64(), and sqlite3_realloc64()
** is always aligned to at least an 8 byte boundary, or to a
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
**
** In SQLite version 3.5.0 and 3.5.1, it was possible to define
** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
** implementation of these routines to be omitted.  That capability
** is no longer provided.  Only built-in memory allocators can be used.
**
** Prior to SQLite version 3.7.10, the Windows OS interface layer called
** the system malloc() and free() directly when converting
** filenames between the UTF-8 encoding used by SQLite
** and whatever filename encoding is used by the particular Windows
** installation.  Memory allocation errors were detected, but
** they were reported back as [SQLITE_CANTOPEN] or
** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
**
** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
** must be either NULL or else pointers obtained from a prior
** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
** not yet been released.
**
** The application must not read or write any part of
** a block of memory after it has been released using







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







3902
3903
3904
3905
3906
3907
3908













3909
3910
3911
3912
3913
3914
3915
**
** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
** sqlite3_malloc64(), and sqlite3_realloc64()
** is always aligned to at least an 8 byte boundary, or to a
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
**













** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
** must be either NULL or else pointers obtained from a prior
** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
** not yet been released.
**
** The application must not read or write any part of
** a block of memory after it has been released using
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947

/*
** CAPI3REF: Pseudo-Random Number Generator
**
** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
** select random [ROWID | ROWIDs] when inserting new records into a table that
** already uses the largest possible [ROWID].  The PRNG is also used for
** the build-in random() and randomblob() SQL functions.  This interface allows
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
** call had N less than one or a NULL pointer for P, then the PRNG is







|







3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964

/*
** CAPI3REF: Pseudo-Random Number Generator
**
** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
** select random [ROWID | ROWIDs] when inserting new records into a table that
** already uses the largest possible [ROWID].  The PRNG is also used for
** the built-in random() and randomblob() SQL functions.  This interface allows
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
** call had N less than one or a NULL pointer for P, then the PRNG is
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334








































4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
** passing it to [sqlite3_close()] when it is no longer required.
**
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
** over the new database connection.  ^(The flags parameter to
** sqlite3_open_v2() can take one of
** the following three values, optionally combined with the 
** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
** <dd>The database is opened in read-only mode.  If the database does not
** already exist, an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
** <dd>The database is opened for reading and writing if possible, or reading
** only if the file is write protected by the operating system.  In either
** case the database must already exist, otherwise an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
** <dd>The database is opened for reading and writing, and is created if
** it does not already exist. This is the behavior that is always used for
** sqlite3_open() and sqlite3_open16().</dd>)^
** </dl>
**








































** If the 3rd parameter to sqlite3_open_v2() is not one of the
** combinations shown above optionally combined with other
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
** then the behavior is undefined.
**
** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
** opens in the multi-thread [threading mode] as long as the single-thread
** mode has not been set at compile-time or start-time.  ^If the
** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens
** in the serialized [threading mode] unless single-thread was
** previously selected at compile-time or start-time.
** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be
** eligible to use [shared cache mode], regardless of whether or not shared
** cache is enabled using [sqlite3_enable_shared_cache()].  ^The
** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
** participate in [shared cache mode] even if it is enabled.
**
** ^The fourth parameter to sqlite3_open_v2() is the name of the
** [sqlite3_vfs] object that defines the operating system interface that
** the new database connection should use.  ^If the fourth parameter is
** a NULL pointer then the default [sqlite3_vfs] object is used.
**
** ^If the filename is ":memory:", then a private, temporary in-memory database
** is created for the connection.  ^This in-memory database will vanish when







|
|
<
<

















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

|



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







4324
4325
4326
4327
4328
4329
4330
4331
4332


4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394












4395
4396
4397
4398
4399
4400
4401
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
** passing it to [sqlite3_close()] when it is no longer required.
**
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
** over the new database connection.  ^(The flags parameter to
** sqlite3_open_v2() must include, at a minimum, one of the following
** three flag combinations:)^


**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
** <dd>The database is opened in read-only mode.  If the database does not
** already exist, an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
** <dd>The database is opened for reading and writing if possible, or reading
** only if the file is write protected by the operating system.  In either
** case the database must already exist, otherwise an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
** <dd>The database is opened for reading and writing, and is created if
** it does not already exist. This is the behavior that is always used for
** sqlite3_open() and sqlite3_open16().</dd>)^
** </dl>
**
** In addition to the required flags, the following optional flags are
** also supported:
**
** <dl>
** ^(<dt>[SQLITE_OPEN_URI]</dt>
** <dd>The filename can be interpreted as a URI if this flag is set.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_MEMORY]</dt>
** <dd>The database will be opened as an in-memory database.  The database
** is named by the "filename" argument for the purposes of cache-sharing,
** if shared cache mode is enabled, but the "filename" is otherwise ignored.
** </dd>)^
**
** ^(<dt>[SQLITE_OPEN_NOMUTEX]</dt>
** <dd>The new database connection will use the "multi-thread"
** [threading mode].)^  This means that separate threads are allowed
** to use SQLite at the same time, as long as each thread is using
** a different [database connection].
**
** ^(<dt>[SQLITE_OPEN_FULLMUTEX]</dt>
** <dd>The new database connection will use the "serialized"
** [threading mode].)^  This means the multiple threads can safely
** attempt to use the same database connection at the same time.
** (Mutexes will block any actual concurrency, but in this mode
** there is no harm in trying.)
**
** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt>
** <dd>The database is opened [shared cache] enabled, overriding
** the default shared cache setting provided by
** [sqlite3_enable_shared_cache()].)^
**
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
** <dd>The database is opened [shared cache] disabled, overriding
** the default shared cache setting provided by
** [sqlite3_enable_shared_cache()].)^
**
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
** <dd>The database filename is not allowed to be a symbolic link</dd>
** </dl>)^
**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
** required combinations shown above optionally combined with other
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
** then the behavior is undefined.
**












** ^The fourth parameter to sqlite3_open_v2() is the name of the
** [sqlite3_vfs] object that defines the operating system interface that
** the new database connection should use.  ^If the fourth parameter is
** a NULL pointer then the default [sqlite3_vfs] object is used.
**
** ^If the filename is ":memory:", then a private, temporary in-memory database
** is created for the connection.  ^This in-memory database will vanish when
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559







4560
4561
4562
4563
4564
4565








4566
4567
4568
4569
4570
4571

4572




















































































4573
4574
4575
4576
4577
4578
4579
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);

/*
** CAPI3REF: Obtain Values For URI Parameters
**
** These are utility routines, useful to VFS implementations, that check
** to see if a database file was a URI that contained a specific query 
** parameter, and if so obtains the value of that query parameter.
**
** If F is the database filename pointer passed into the xOpen() method of 
** a VFS implementation when the flags parameter to xOpen() has one or 
** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and
** P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
** parameter if it exists or a NULL pointer if P does not appear as a 
** query parameter on F.  If P is a query parameter of F
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
** a pointer to an empty string.
**
** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean
** parameter and returns true (1) or false (0) according to the value
** of P.  The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
** value of query parameter P is one of "yes", "true", or "on" in any
** case or if the value begins with a non-zero number.  The 
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
** query parameter P is one of "no", "false", or "off" in any case or
** if the value begins with a numeric zero.  If P is not a query
** parameter on F or if the value of P is does not match any of the
** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
**
** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
** 64-bit signed integer and returns that integer, or D if P does not
** exist.  If the value of P is something other than an integer, then
** zero is returned.







** 
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
** sqlite3_uri_boolean(F,P,B) returns B.  If F is not a NULL pointer and
** is not a database file pathname pointer that SQLite passed into the xOpen
** VFS method, then the behavior of this routine is undefined and probably
** undesirable.








**
** See the [URI filename] documentation for additional information.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);























































































/*
** CAPI3REF: Error Codes And Messages
** METHOD: sqlite3
**
** ^If the most recent sqlite3_* API call associated with 
** [database connection] D failed, then the sqlite3_errcode(D) interface







|
|



|
<
|


|











|






>
>
>
>
>
>
>



|
|
|
>
>
>
>
>
>
>
>






>

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







4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579

4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);

/*
** CAPI3REF: Obtain Values For URI Parameters
**
** These are utility routines, useful to [VFS|custom VFS implementations],
** that check if a database file was a URI that contained a specific query 
** parameter, and if so obtains the value of that query parameter.
**
** If F is the database filename pointer passed into the xOpen() method of 
** a VFS implementation or it is the return value of [sqlite3_db_filename()]

** and if P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
** parameter if it exists or a NULL pointer if P does not appear as a 
** query parameter on F.  If P is a query parameter of F and it
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
** a pointer to an empty string.
**
** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean
** parameter and returns true (1) or false (0) according to the value
** of P.  The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
** value of query parameter P is one of "yes", "true", or "on" in any
** case or if the value begins with a non-zero number.  The 
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
** query parameter P is one of "no", "false", or "off" in any case or
** if the value begins with a numeric zero.  If P is not a query
** parameter on F or if the value of P does not match any of the
** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
**
** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
** 64-bit signed integer and returns that integer, or D if P does not
** exist.  If the value of P is something other than an integer, then
** zero is returned.
**
** The sqlite3_uri_key(F,N) returns a pointer to the name (not
** the value) of the N-th query parameter for filename F, or a NULL
** pointer if N is less than zero or greater than the number of query
** parameters minus 1.  The N value is zero-based so N should be 0 to obtain
** the name of the first query parameter, 1 for the second parameter, and
** so forth.
** 
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
** sqlite3_uri_boolean(F,P,B) returns B.  If F is not a NULL pointer and
** is not a database file pathname pointer that the SQLite core passed
** into the xOpen VFS method, then the behavior of this routine is undefined
** and probably undesirable.
**
** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F
** parameter can also be the name of a rollback journal file or WAL file
** in addition to the main database file.  Prior to version 3.31.0, these
** routines would only work if F was the name of the main database file.
** When the F parameter is the name of the rollback journal or WAL file,
** it has access to all the same query parameters as were found on the
** main database file.
**
** See the [URI filename] documentation for additional information.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);

/*
** CAPI3REF:  Translate filenames
**
** These routines are available to [VFS|custom VFS implementations] for
** translating filenames between the main database file, the journal file,
** and the WAL file.
**
** If F is the name of an sqlite database file, journal file, or WAL file
** passed by the SQLite core into the VFS, then sqlite3_filename_database(F)
** returns the name of the corresponding database file.
**
** If F is the name of an sqlite database file, journal file, or WAL file
** passed by the SQLite core into the VFS, or if F is a database filename
** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F)
** returns the name of the corresponding rollback journal file.
**
** If F is the name of an sqlite database file, journal file, or WAL file
** that was passed by the SQLite core into the VFS, or if F is a database
** filename obtained from [sqlite3_db_filename()], then
** sqlite3_filename_wal(F) returns the name of the corresponding
** WAL file.
**
** In all of the above, if F is not the name of a database, journal or WAL
** filename passed into the VFS from the SQLite core and F is not the
** return value from [sqlite3_db_filename()], then the result is
** undefined and is likely a memory access violation.
*/
SQLITE_API const char *sqlite3_filename_database(const char*);
SQLITE_API const char *sqlite3_filename_journal(const char*);
SQLITE_API const char *sqlite3_filename_wal(const char*);

/*
** CAPI3REF: Create and Destroy VFS Filenames
**
** These interfces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
** database filename D with corresponding journal file J and WAL file W and
** with N URI parameters key/values pairs in the array P.  The result from
** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
** is safe to pass to routines like:
** <ul>
** <li> [sqlite3_uri_parameter()],
** <li> [sqlite3_uri_boolean()],
** <li> [sqlite3_uri_int64()],
** <li> [sqlite3_uri_key()], 
** <li> [sqlite3_filename_database()],
** <li> [sqlite3_filename_journal()], or
** <li> [sqlite3_filename_wal()].
** </ul>
** If a memory allocation error occurs, sqlite3_create_filename() might
** return a NULL pointer.  The memory obtained from sqlite3_create_filename(X)
** must be released by a corresponding call to sqlite3_free_filename(Y).
**
** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array
** of 2*N pointers to strings.  Each pair of pointers in this array corresponds
** to a key and value for a query parameter.  The P parameter may be a NULL
** pointer if N is zero.  None of the 2*N pointers in the P array may be
** NULL pointers and key pointers should not be empty strings.
** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may
** be NULL pointers, though they can be empty strings.
**
** The sqlite3_free_filename(Y) routine releases a memory allocation
** previously obtained from sqlite3_create_filename().  Invoking
** sqlite3_free_filename(Y) is a NULL pointer is a harmless no-op.
**
** If the Y parameter to sqlite3_free_filename(Y) is anything other
** than a NULL pointer or a pointer previously acquired from
** sqlite3_create_filename(), then bad things such as heap
** corruption or segfaults may occur. The value Y should be 
** used again after sqlite3_free_filename(Y) has been called.  This means
** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
** then the corresponding [sqlite3_module.xClose() method should also be
** invoked prior to calling sqlite3_free_filename(Y).
*/
SQLITE_API char *sqlite3_create_filename(
  const char *zDatabase,
  const char *zJournal,
  const char *zWal,
  int nParam,
  const char **azParam
);
SQLITE_API void sqlite3_free_filename(char*);

/*
** CAPI3REF: Error Codes And Messages
** METHOD: sqlite3
**
** ^If the most recent sqlite3_* API call associated with 
** [database connection] D failed, then the sqlite3_errcode(D) interface
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code
** and the application would have to make a second call to [sqlite3_reset()]
** in order to find the underlying cause of the problem. With the "v2" prepare
** interfaces, the underlying reason for the error is returned immediately.
** </li>
**
** <li>
** ^If the specific value bound to [parameter | host parameter] in the 
** WHERE clause might influence the choice of query plan for a statement,
** then the statement will be automatically recompiled, as if there had been 
** a schema change, on the first  [sqlite3_step()] call following any change
** to the [sqlite3_bind_text | bindings] of that [parameter]. 
** ^The specific value of WHERE-clause [parameter] might influence the 
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
** </li>
** </ol>
**
** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having







|


|

|







5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code
** and the application would have to make a second call to [sqlite3_reset()]
** in order to find the underlying cause of the problem. With the "v2" prepare
** interfaces, the underlying reason for the error is returned immediately.
** </li>
**
** <li>
** ^If the specific value bound to a [parameter | host parameter] in the 
** WHERE clause might influence the choice of query plan for a statement,
** then the statement will be automatically recompiled, as if there had been 
** a schema change, on the first [sqlite3_step()] call following any change
** to the [sqlite3_bind_text | bindings] of that [parameter]. 
** ^The specific value of a WHERE-clause [parameter] might influence the 
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
** </li>
** </ol>
**
** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160


















5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
** ^The leftmost SQL parameter has an index of 1.  ^When the same named
** SQL parameter is used more than once, second and subsequent
** occurrences have the same index as the first occurrence.
** ^The index for named parameters can be looked up using the
** [sqlite3_bind_parameter_index()] API if desired.  ^The index
** for "?NNN" parameters is the value of NNN.
** ^The NNN value must be between 1 and the [sqlite3_limit()]
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
**
** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().


















**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter.  To be clear: the value is the
** number of <u>bytes</u> in the value, not the number of characters.)^
** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** is negative, then the length of the string is
** the number of bytes up to the first zero terminator.
** If the fourth parameter to sqlite3_bind_blob() is negative, then
** the behavior is undefined.
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated.  If any NUL characters occur at byte offsets less than 
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs.  The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it.  ^The destructor is called







|





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













|







5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
** ^The leftmost SQL parameter has an index of 1.  ^When the same named
** SQL parameter is used more than once, second and subsequent
** occurrences have the same index as the first occurrence.
** ^The index for named parameters can be looked up using the
** [sqlite3_bind_parameter_index()] API if desired.  ^The index
** for "?NNN" parameters is the value of NNN.
** ^The NNN value must be between 1 and the [sqlite3_limit()]
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766).
**
** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().
** ^If the third parameter to sqlite3_bind_text() is not NULL, then
** it should be a pointer to well-formed UTF8 text.
** ^If the third parameter to sqlite3_bind_text16() is not NULL, then
** it should be a pointer to well-formed UTF16 text.
** ^If the third parameter to sqlite3_bind_text64() is not NULL, then
** it should be a pointer to a well-formed unicode string that is
** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16
** otherwise.
**
** [[byte-order determination rules]] ^The byte-order of
** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
** found in first character, which is removed, or in the absence of a BOM
** the byte order is the native byte order of the host
** machine for sqlite3_bind_text16() or the byte order specified in
** the 6th parameter for sqlite3_bind_text64().)^ 
** ^If UTF16 input text contains invalid unicode
** characters, then SQLite might change those invalid characters
** into the unicode replacement character: U+FFFD.
**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter.  To be clear: the value is the
** number of <u>bytes</u> in the value, not the number of characters.)^
** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** is negative, then the length of the string is
** the number of bytes up to the first zero terminator.
** If the fourth parameter to sqlite3_bind_blob() is negative, then
** the behavior is undefined.
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated.  If any NUL characters occurs at byte offsets less than 
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs.  The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it.  ^The destructor is called
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
** ^The first argument to these interfaces is a [prepared statement].
** ^These functions return information about the Nth result column returned by
** the statement, where N is the second function argument.
** ^The left-most column is column 0 for these routines.
**
** ^If the Nth column returned by the statement is an expression or
** subquery and is not a column value, then all of these functions return
** NULL.  ^These routine might also return NULL if a memory allocation error
** occurs.  ^Otherwise, they return the name of the attached database, table,
** or column that query result column was extracted from.
**
** ^As with all other SQLite APIs, those whose names end with "16" return
** UTF-16 encoded strings and the other functions return UTF-8.
**
** ^These APIs are only available if the library was compiled with the
** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
**
** If two or more threads call one or more of these routines against the same
** prepared statement and column at the same time then the results are
** undefined.
**
** If two or more threads call one or more
** [sqlite3_column_database_name | column metadata interfaces]
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);







|









<
<
<
<







5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573




5574
5575
5576
5577
5578
5579
5580
** ^The first argument to these interfaces is a [prepared statement].
** ^These functions return information about the Nth result column returned by
** the statement, where N is the second function argument.
** ^The left-most column is column 0 for these routines.
**
** ^If the Nth column returned by the statement is an expression or
** subquery and is not a column value, then all of these functions return
** NULL.  ^These routines might also return NULL if a memory allocation error
** occurs.  ^Otherwise, they return the name of the attached database, table,
** or column that query result column was extracted from.
**
** ^As with all other SQLite APIs, those whose names end with "16" return
** UTF-16 encoded strings and the other functions return UTF-8.
**
** ^These APIs are only available if the library was compiled with the
** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
**




** If two or more threads call one or more
** [sqlite3_column_database_name | column metadata interfaces]
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
/*
** CAPI3REF: Number of columns in a result set
** METHOD: sqlite3_stmt
**
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
** ^If prepared statement P does not have results ready to return
** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
** interfaces) then sqlite3_data_count(P) returns 0.
** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
** [sqlite3_step](P) returned [SQLITE_DONE].  ^The sqlite3_data_count(P)
** will return non-zero if previous call to [sqlite3_step](P) returned
** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum]
** where it always returns zero since each step of that multi-step







|







5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
/*
** CAPI3REF: Number of columns in a result set
** METHOD: sqlite3_stmt
**
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
** ^If prepared statement P does not have results ready to return
** (via calls to the [sqlite3_column_int | sqlite3_column()] family of
** interfaces) then sqlite3_data_count(P) returns 0.
** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
** [sqlite3_step](P) returned [SQLITE_DONE].  ^The sqlite3_data_count(P)
** will return non-zero if previous call to [sqlite3_step](P) returned
** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum]
** where it always returns zero since each step of that multi-step
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);

/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
** KEYWORDS: {application-defined SQL function}
** KEYWORDS: {application-defined SQL functions}
** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
** of existing SQL functions or aggregates. The only differences between
** the three "sqlite3_create_function*" routines are the text encoding 
** expected for the second parameter (the name of the function being 







<
<







6027
6028
6029
6030
6031
6032
6033


6034
6035
6036
6037
6038
6039
6040
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);

/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}


** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
** of existing SQL functions or aggregates. The only differences between
** the three "sqlite3_create_function*" routines are the text encoding 
** expected for the second parameter (the name of the function being 
5928
5929
5930
5931
5932
5933
5934




5935
5936







5937
5938
5939
5940
5941
5942
5943
5944
** deterministic.  The built-in [random()] SQL function is an example of a
** function that is not deterministic.  The SQLite query planner is able to
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
** flag, which if present prevents the function from being invoked from




** within VIEWs or TRIGGERs.  For security reasons, the [SQLITE_DIRECTONLY]
** flag is recommended for any application-defined SQL function that has







** side-effects.
**
** ^(The fifth parameter is an arbitrary pointer.  The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
**
** ^The sixth, seventh and eighth parameters passed to the three
** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are
** pointers to C-language functions that implement the SQL function or







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







6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
** deterministic.  The built-in [random()] SQL function is an example of a
** function that is not deterministic.  The SQLite query planner is able to
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
** flag, which if present prevents the function from being invoked from
** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
** index expressions, or the WHERE clause of partial indexes.
**
** <span style="background-color:#ffff90;">
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
** all application-defined SQL functions that do not need to be
** used inside of triggers, view, CHECK constraints, or other elements of
** the database schema.  This flags is especially recommended for SQL 
** functions that have side effects or reveal internal application state.
** Without this flag, an attacker might be able to modify the schema of
** a database file to include invocations of the function with parameters
** chosen by the attacker, which the application will then execute when
** the database file is opened and read.
** </span>
**
** ^(The fifth parameter is an arbitrary pointer.  The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
**
** ^The sixth, seventh and eighth parameters passed to the three
** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are
** pointers to C-language functions that implement the SQL function or
6049
6050
6051
6052
6053
6054
6055


6056
6057
6058






6059

6060
6061


6062
6063

















6064




6065


6066
6067

6068
6069
6070
6071
6072
6073
6074


6075
6076
6077
6078

6079
6080
6081
6082
6083
6084
6085
** CAPI3REF: Function Flags
**
** These constants may be ORed together with the 
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
**


** The SQLITE_DETERMINISTIC flag means that the new function will always
** maps the same inputs into the same output.  The abs() function is
** deterministic, for example, but randomblob() is not.






**

** The SQLITE_DIRECTONLY flag means that the function may only be invoked
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs.  This is


** a security feature which is recommended for all 
** [application-defined SQL functions] that have side-effects.  This flag 

















** prevents an attacker from adding triggers and views to a schema then 




** tricking a high-privilege application into causing unintended side-effects


** while performing ordinary queries.
**

** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
** Specifying this flag makes no difference for scalar or aggregate user
** functions. However, if it is not specified for a user-defined window
** function, then any sub-types belonging to arguments passed to the window
** function may be discarded before the window function is called (i.e.
** sqlite3_value_subtype() will always return 0).


*/
#define SQLITE_DETERMINISTIC    0x000000800
#define SQLITE_DIRECTONLY       0x000080000
#define SQLITE_SUBTYPE          0x000100000


/*
** CAPI3REF: Deprecated Functions
** DEPRECATED
**
** These functions are [deprecated].  In order to maintain
** backwards compatibility with older code, these functions continue 







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

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

>







>
>




>







6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
** CAPI3REF: Function Flags
**
** These constants may be ORed together with the 
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
**
** <dl>
** [[SQLITE_DETERMINISTIC]] <dt>SQLITE_DETERMINISTIC</dt><dd>
** The SQLITE_DETERMINISTIC flag means that the new function always gives
** the same output when the input parameters are the same.
** The [abs|abs() function] is deterministic, for example, but
** [randomblob|randomblob()] is not.  Functions must
** be deterministic in order to be used in certain contexts such as
** with the WHERE clause of [partial indexes] or in [generated columns].
** SQLite might also optimize deterministic functions by factoring them
** out of inner loops.
** </dd>
** 
** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd>
** The SQLITE_DIRECTONLY flag means that the function may only be invoked
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in 
** schema structures such as [CHECK constraints], [DEFAULT clauses],
** [expression indexes], [partial indexes], or [generated columns].
** The SQLITE_DIRECTONLY flags is a security feature which is recommended
** for all [application-defined SQL functions], and especially for functions
** that have side-effects or that could potentially leak sensitive
** information.
** </dd>
**
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
** The SQLITE_INNOCUOUS flag means that the function is unlikely
** to cause problems even if misused.  An innocuous function should have
** no side effects and should not depend on any values other than its
** input parameters. The [abs|abs() function] is an example of an
** innocuous function.
** The [load_extension() SQL function] is not innocuous because of its
** side effects.
** <p> SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not
** exactly the same.  The [random|random() function] is an example of a
** function that is innocuous but not deterministic.
** <p>Some heightened security settings
** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF])
** disable the use of SQL functions inside views and triggers and in
** schema structures such as [CHECK constraints], [DEFAULT clauses],
** [expression indexes], [partial indexes], and [generated columns] unless
** the function is tagged with SQLITE_INNOCUOUS.  Most built-in functions
** are innocuous.  Developers are advised to avoid using the
** SQLITE_INNOCUOUS flag for application-defined functions unless the
** function has been carefully audited and found to be free of potentially
** security-adverse side-effects and information-leaks.
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
** Specifying this flag makes no difference for scalar or aggregate user
** functions. However, if it is not specified for a user-defined window
** function, then any sub-types belonging to arguments passed to the window
** function may be discarded before the window function is called (i.e.
** sqlite3_value_subtype() will always return 0).
** </dd>
** </dl>
*/
#define SQLITE_DETERMINISTIC    0x000000800
#define SQLITE_DIRECTONLY       0x000080000
#define SQLITE_SUBTYPE          0x000100000
#define SQLITE_INNOCUOUS        0x000200000

/*
** CAPI3REF: Deprecated Functions
** DEPRECATED
**
** These functions are [deprecated].  In order to maintain
** backwards compatibility with older code, these functions continue 
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
** <td>&rarr;&nbsp;&nbsp;<td>True if value originated from a [bound parameter]
** </table></blockquote>
**
** <b>Details:</b>
**
** These routines extract type, size, and content information from
** [protected sqlite3_value] objects.  Protected sqlite3_value objects
** are used to pass parameter information into implementation of
** [application-defined SQL functions] and [virtual tables].
**
** These routines work only with [protected sqlite3_value] objects.
** Any attempt to use these routines on an [unprotected sqlite3_value]
** is not threadsafe.
**
** ^These routines work just like the corresponding [column access functions]
** except that these routines take a single [protected sqlite3_value] object







|
|







6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
** <td>&rarr;&nbsp;&nbsp;<td>True if value originated from a [bound parameter]
** </table></blockquote>
**
** <b>Details:</b>
**
** These routines extract type, size, and content information from
** [protected sqlite3_value] objects.  Protected sqlite3_value objects
** are used to pass parameter information into the functions that
** implement [application-defined SQL functions] and [virtual tables].
**
** These routines work only with [protected sqlite3_value] objects.
** Any attempt to use these routines on an [unprotected sqlite3_value]
** is not threadsafe.
**
** ^These routines work just like the corresponding [column access functions]
** except that these routines take a single [protected sqlite3_value] object
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
** than within an [xUpdate] method call for an UPDATE statement, then
** the return value is arbitrary and meaningless.
**
** ^The sqlite3_value_frombind(X) interface returns non-zero if the
** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()]
** interfaces.  ^If X comes from an SQL literal value, or a table column,
** and expression, then sqlite3_value_frombind(X) returns zero.
**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
** [sqlite3_value_text16()] can be invalidated by a subsequent call to
** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
** or [sqlite3_value_text16()].
**







|







6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
** than within an [xUpdate] method call for an UPDATE statement, then
** the return value is arbitrary and meaningless.
**
** ^The sqlite3_value_frombind(X) interface returns non-zero if the
** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()]
** interfaces.  ^If X comes from an SQL literal value, or a table column,
** or an expression, then sqlite3_value_frombind(X) returns zero.
**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
** [sqlite3_value_text16()] can be invalidated by a subsequent call to
** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
** or [sqlite3_value_text16()].
**
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
** CAPI3REF: Obtain Aggregate Function Context
** METHOD: sqlite3_context
**
** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
**
** ^The first time the sqlite3_aggregate_context(C,N) routine is called 
** for a particular aggregate function, SQLite
** allocates N of memory, zeroes out that memory, and returns a pointer
** to the new memory. ^On second and subsequent calls to
** sqlite3_aggregate_context() for the same aggregate function instance,
** the same buffer is returned.  Sqlite3_aggregate_context() is normally
** called once for each invocation of the xStep callback and then one
** last time when the xFinal callback is invoked.  ^(When no rows match
** an aggregate query, the xStep() callback of the aggregate function
** implementation is never called and xFinal() is called exactly once.
** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^
**
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer 
** when first called if N is less than or equal to zero or if a memory
** allocate error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call.  Changing the
** value of N in subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
** allocation.)^  Within the xFinal callback, it is customary to set
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no 
** pointless memory allocations occur.
**
** ^SQLite automatically frees the memory allocated by 
** sqlite3_aggregate_context() when the aggregate query concludes.







|
|
















|







6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
** CAPI3REF: Obtain Aggregate Function Context
** METHOD: sqlite3_context
**
** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
**
** ^The first time the sqlite3_aggregate_context(C,N) routine is called 
** for a particular aggregate function, SQLite allocates
** N bytes of memory, zeroes out that memory, and returns a pointer
** to the new memory. ^On second and subsequent calls to
** sqlite3_aggregate_context() for the same aggregate function instance,
** the same buffer is returned.  Sqlite3_aggregate_context() is normally
** called once for each invocation of the xStep callback and then one
** last time when the xFinal callback is invoked.  ^(When no rows match
** an aggregate query, the xStep() callback of the aggregate function
** implementation is never called and xFinal() is called exactly once.
** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^
**
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer 
** when first called if N is less than or equal to zero or if a memory
** allocate error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call.  Changing the
** value of N in any subsequents call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
** allocation.)^  Within the xFinal callback, it is customary to set
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no 
** pointless memory allocations occur.
**
** ^SQLite automatically frees the memory allocated by 
** sqlite3_aggregate_context() when the aggregate query concludes.
6449
6450
6451
6452
6453
6454
6455
6456

6457
6458
6459
6460
6461
6462
6463
6464
**
** ^The sqlite3_result_error() and sqlite3_result_error16() functions
** cause the implemented SQL function to throw an exception.
** ^SQLite uses the string pointed to by the
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
** as the text of an error message.  ^SQLite interprets the error
** message string from sqlite3_result_error() as UTF-8. ^SQLite
** interprets the string from sqlite3_result_error16() as UTF-16 in native

** byte order.  ^If the third parameter to sqlite3_result_error()
** or sqlite3_result_error16() is negative then SQLite takes as the error
** message all text up through the first zero character.
** ^If the third parameter to sqlite3_result_error() or
** sqlite3_result_error16() is non-negative then SQLite takes that many
** bytes (not characters) from the 2nd parameter as the error message.
** ^The sqlite3_result_error() and sqlite3_result_error16()
** routines make a private copy of the error message text before







|
>
|







6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
**
** ^The sqlite3_result_error() and sqlite3_result_error16() functions
** cause the implemented SQL function to throw an exception.
** ^SQLite uses the string pointed to by the
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
** as the text of an error message.  ^SQLite interprets the error
** message string from sqlite3_result_error() as UTF-8. ^SQLite
** interprets the string from sqlite3_result_error16() as UTF-16 using
** the same [byte-order determination rules] as [sqlite3_bind_text16()].
** ^If the third parameter to sqlite3_result_error()
** or sqlite3_result_error16() is negative then SQLite takes as the error
** message all text up through the first zero character.
** ^If the third parameter to sqlite3_result_error() or
** sqlite3_result_error16() is non-negative then SQLite takes that many
** bytes (not characters) from the 2nd parameter as the error message.
** ^The sqlite3_result_error() and sqlite3_result_error16()
** routines make a private copy of the error message text before
6517
6518
6519
6520
6521
6522
6523



















6524
6525
6526
6527
6528
6529
6530
** assumes that the text or BLOB result is in constant space and does not
** copy the content of the parameter nor call a destructor on the content
** when it has finished using that result.
** ^If the 4th parameter to the sqlite3_result_text* interfaces
** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
** then SQLite makes a copy of the result into space obtained
** from [sqlite3_malloc()] before it returns.



















**
** ^The sqlite3_result_value() interface sets the result of
** the application-defined function to be a copy of the
** [unprotected sqlite3_value] object specified by the 2nd parameter.  ^The
** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
** so that the [sqlite3_value] specified in the parameter may change or
** be deallocated after sqlite3_result_value() returns without harm.







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







6721
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
** assumes that the text or BLOB result is in constant space and does not
** copy the content of the parameter nor call a destructor on the content
** when it has finished using that result.
** ^If the 4th parameter to the sqlite3_result_text* interfaces
** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
** then SQLite makes a copy of the result into space obtained
** from [sqlite3_malloc()] before it returns.
**
** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and
** sqlite3_result_text16be() routines, and for sqlite3_result_text64()
** when the encoding is not UTF8, if the input UTF16 begins with a
** byte-order mark (BOM, U+FEFF) then the BOM is removed from the
** string and the rest of the string is interpreted according to the
** byte-order specified by the BOM.  ^The byte-order specified by
** the BOM at the beginning of the text overrides the byte-order
** specified by the interface procedure.  ^So, for example, if
** sqlite3_result_text16le() is invoked with text that begins
** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the
** first two bytes of input are skipped and the remaining input
** is interpreted as UTF16BE text.
**
** ^For UTF16 input text to the sqlite3_result_text16(),
** sqlite3_result_text16be(), sqlite3_result_text16le(), and
** sqlite3_result_text64() routines, if the text contains invalid
** UTF16 characters, the invalid characters might be converted
** into the unicode replacement character, U+FFFD.
**
** ^The sqlite3_result_value() interface sets the result of
** the application-defined function to be a copy of the
** [unprotected sqlite3_value] object specified by the 2nd parameter.  ^The
** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
** so that the [sqlite3_value] specified in the parameter may change or
** be deallocated after sqlite3_result_value() returns without harm.
6603
6604
6605
6606
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629

6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
** <li> [SQLITE_UTF8],
** <li> [SQLITE_UTF16LE],
** <li> [SQLITE_UTF16BE],
** <li> [SQLITE_UTF16], or
** <li> [SQLITE_UTF16_ALIGNED].
** </ul>)^
** ^The eTextRep argument determines the encoding of strings passed
** to the collating function callback, xCallback.
** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
** force strings to be UTF16 with native byte order.
** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
** on an even byte address.
**
** ^The fourth argument, pArg, is an application data pointer that is passed
** through as the first argument to the collating function callback.
**
** ^The fifth argument, xCallback, is a pointer to the collating function.
** ^Multiple collating functions can be registered using the same name but
** with different eTextRep parameters and SQLite will use whichever
** function requires the least amount of data transformation.
** ^If the xCallback argument is NULL then the collating function is
** deleted.  ^When all collating functions having the same name are deleted,
** that collation is no longer usable.
**
** ^The collating function callback is invoked with a copy of the pArg 
** application data pointer and with two strings in the encoding specified
** by the eTextRep argument.  The collating function must return an

** integer that is negative, zero, or positive
** if the first string is less than, equal to, or greater than the second,
** respectively.  A collating function must always return the same answer
** given the same inputs.  If two or more collating functions are registered
** to the same collation name (using different eTextRep values) then all
** must give an equivalent answer when invoked with equivalent strings.
** The collating function must obey the following properties for all
** strings A, B, and C:
**
** <ol>
** <li> If A==B then B==A.
** <li> If A==B and B==C then A==C.
** <li> If A&lt;B THEN B&gt;A.
** <li> If A&lt;B and B&lt;C then A&lt;C.
** </ol>
**
** If a collating function fails any of the above constraints and that
** collating function is  registered and used, then the behavior of SQLite
** is undefined.
**
** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
** with the addition that the xDestroy callback is invoked on pArg when
** the collating function is deleted.
** ^Collating functions are deleted when they are overridden by later
** calls to the collation creation functions or when the







|








|



|





|
>
|
















|







6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
6877
6878
** <li> [SQLITE_UTF8],
** <li> [SQLITE_UTF16LE],
** <li> [SQLITE_UTF16BE],
** <li> [SQLITE_UTF16], or
** <li> [SQLITE_UTF16_ALIGNED].
** </ul>)^
** ^The eTextRep argument determines the encoding of strings passed
** to the collating function callback, xCompare.
** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
** force strings to be UTF16 with native byte order.
** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
** on an even byte address.
**
** ^The fourth argument, pArg, is an application data pointer that is passed
** through as the first argument to the collating function callback.
**
** ^The fifth argument, xCompare, is a pointer to the collating function.
** ^Multiple collating functions can be registered using the same name but
** with different eTextRep parameters and SQLite will use whichever
** function requires the least amount of data transformation.
** ^If the xCompare argument is NULL then the collating function is
** deleted.  ^When all collating functions having the same name are deleted,
** that collation is no longer usable.
**
** ^The collating function callback is invoked with a copy of the pArg 
** application data pointer and with two strings in the encoding specified
** by the eTextRep argument.  The two integer parameters to the collating
** function callback are the length of the two strings, in bytes. The collating
** function must return an integer that is negative, zero, or positive
** if the first string is less than, equal to, or greater than the second,
** respectively.  A collating function must always return the same answer
** given the same inputs.  If two or more collating functions are registered
** to the same collation name (using different eTextRep values) then all
** must give an equivalent answer when invoked with equivalent strings.
** The collating function must obey the following properties for all
** strings A, B, and C:
**
** <ol>
** <li> If A==B then B==A.
** <li> If A==B and B==C then A==C.
** <li> If A&lt;B THEN B&gt;A.
** <li> If A&lt;B and B&lt;C then A&lt;C.
** </ol>
**
** If a collating function fails any of the above constraints and that
** collating function is registered and used, then the behavior of SQLite
** is undefined.
**
** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
** with the addition that the xDestroy callback is invoked on pArg when
** the collating function is deleted.
** ^Collating functions are deleted when they are overridden by later
** calls to the collation creation functions or when the
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
6775
6776
6777
6778
6779
6780
);
SQLITE_API int sqlite3_collation_needed16(
  sqlite3*, 
  void*,
  void(*)(void*,sqlite3*,int eTextRep,const void*)
);

#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database.  This routine should be
** called right after sqlite3_open().
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
SQLITE_API int sqlite3_key(
  sqlite3 *db,                   /* Database to be rekeyed */
  const void *pKey, int nKey     /* The key */
);
SQLITE_API int sqlite3_key_v2(
  sqlite3 *db,                   /* Database to be rekeyed */
  const char *zDbName,           /* Name of the database */
  const void *pKey, int nKey     /* The key */
);

/*
** Change the key on an open database.  If the current database is not
** encrypted, this routine will encrypt it.  If pNew==0 or nNew==0, the
** database is decrypted.
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
SQLITE_API int sqlite3_rekey(
  sqlite3 *db,                   /* Database to be rekeyed */
  const void *pKey, int nKey     /* The new key */
);
SQLITE_API int sqlite3_rekey_v2(
  sqlite3 *db,                   /* Database to be rekeyed */
  const char *zDbName,           /* Name of the database */
  const void *pKey, int nKey     /* The new key */
);

/*
** Specify the activation key for a SEE database.  Unless 
** activated, none of the SEE routines will work.
*/
SQLITE_API void sqlite3_activate_see(
  const char *zPassPhrase        /* Activation phrase */
);
#endif

#ifdef SQLITE_ENABLE_CEROD
/*
** Specify the activation key for a CEROD database.  Unless 
** activated, none of the CEROD routines will work.
*/
SQLITE_API void sqlite3_activate_cerod(
  const char *zPassPhrase        /* Activation phrase */







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







6946
6947
6948
6949
6950
6951
6952













































6953
6954
6955
6956
6957
6958
6959
);
SQLITE_API int sqlite3_collation_needed16(
  sqlite3*, 
  void*,
  void(*)(void*,sqlite3*,int eTextRep,const void*)
);














































#ifdef SQLITE_ENABLE_CEROD
/*
** Specify the activation key for a CEROD database.  Unless 
** activated, none of the CEROD routines will work.
*/
SQLITE_API void sqlite3_activate_cerod(
  const char *zPassPhrase        /* Activation phrase */
6967
6968
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978




6979
6980
6981
6982
6983











6984
6985
6986
6987
6988
6989
6990
*/
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);

/*
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
** associated with database N of connection D.  ^The main database file
** has the name "main".  If there is no attached database N on the database
** connection D, or if database N is a temporary or in-memory database, then
** this function will return either a NULL pointer or an empty string.




**
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS].  ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.











*/
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);

/*
** CAPI3REF: Determine if a database is read-only
** METHOD: sqlite3
**







|
|
|


>
>
>
>





>
>
>
>
>
>
>
>
>
>
>







7146
7147
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
*/
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);

/*
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename
** associated with database N of connection D.
** ^If there is no attached database N on the database
** connection D, or if database N is a temporary or in-memory database, then
** this function will return either a NULL pointer or an empty string.
**
** ^The string value returned by this routine is owned and managed by
** the database connection.  ^The value will be valid until the database N
** is [DETACH]-ed or until the database connection closes.
**
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS].  ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
**
** If the filename pointer returned by this routine is not NULL, then it
** can be used as the filename input parameter to these routines:
** <ul>
** <li> [sqlite3_uri_parameter()]
** <li> [sqlite3_uri_boolean()]
** <li> [sqlite3_uri_int64()]
** <li> [sqlite3_filename_database()]
** <li> [sqlite3_filename_journal()]
** <li> [sqlite3_filename_wal()]
** </ul>
*/
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);

/*
** CAPI3REF: Determine if a database is read-only
** METHOD: sqlite3
**
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141




7142
7143
7144
7145
7146
7147
7148
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). 
** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
** Existing database connections continue use the sharing mode
** that was in effect at the time they were opened.)^
**
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully.  An [error code] is returned otherwise.)^
**
** ^Shared cache is disabled by default. But this might change in
** future releases of SQLite.  Applications that care about shared
** cache setting should set it explicitly.




**
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
** and will always return SQLITE_MISUSE. On those systems, 
** shared cache mode should be enabled per-database connection via 
** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
**
** This interface is threadsafe on processors where writing a







|





|
|
|
>
>
>
>







7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). 
** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
** Existing database connections continue to use the sharing mode
** that was in effect at the time they were opened.)^
**
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully.  An [error code] is returned otherwise.)^
**
** ^Shared cache is disabled by default. It is recommended that it stay
** that way.  In other words, do not use this routine.  This interface
** continues to be provided for historical compatibility, but its use is
** discouraged.  Any use of shared cache is discouraged.  If shared cache
** must be used, it is recommended that shared cache only be enabled for
** individual database connections using the [sqlite3_open_v2()] interface
** with the [SQLITE_OPEN_SHAREDCACHE] flag.
**
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
** and will always return SQLITE_MISUSE. On those systems, 
** shared cache mode should be enabled per-database connection via 
** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
**
** This interface is threadsafe on processors where writing a
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
**
** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
** information about column C of table T in database D
** on [database connection] X.)^  ^The sqlite3_table_column_metadata()
** interface returns SQLITE_OK and fills in the non-NULL pointers in
** the final five arguments with appropriate values if the specified
** column exists.  ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR and if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
** does not.  If the table name parameter T in a call to
** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
** undefined behavior.
**







|







7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
**
** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
** information about column C of table T in database D
** on [database connection] X.)^  ^The sqlite3_table_column_metadata()
** interface returns SQLITE_OK and fills in the non-NULL pointers in
** the final five arguments with appropriate values if the specified
** column exists.  ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
** does not.  If the table name parameter T in a call to
** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
** undefined behavior.
**
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
**
** ^This interface enables or disables both the C-API
** [sqlite3_load_extension()] and the SQL function [load_extension()].
** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
** to enable or disable only the C-API.)^
**
** <b>Security warning:</b> It is recommended that extension loading
** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
** rather than this interface, so the [load_extension()] SQL function
** remains disabled. This will prevent SQL injections from giving attackers
** access to extension loading capabilities.
*/
SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);

/*







|







7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
**
** ^This interface enables or disables both the C-API
** [sqlite3_load_extension()] and the SQL function [load_extension()].
** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
** to enable or disable only the C-API.)^
**
** <b>Security warning:</b> It is recommended that extension loading
** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
** rather than this interface, so the [load_extension()] SQL function
** remains disabled. This will prevent SQL injections from giving attackers
** access to extension loading capabilities.
*/
SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);

/*
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
typedef struct sqlite3_module sqlite3_module;

/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
**
** This structure, sometimes called a "virtual table module", 
** defines the implementation of a [virtual tables].  
** This structure consists mostly of methods for the module.
**
** ^A virtual table module is created by filling in a persistent
** instance of this structure and passing a pointer to that instance
** to [sqlite3_create_module()] or [sqlite3_create_module_v2()].
** ^The registration remains valid until it is replaced by a different
** module or until the [database connection] closes.  The content







|







7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
typedef struct sqlite3_module sqlite3_module;

/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
**
** This structure, sometimes called a "virtual table module", 
** defines the implementation of a [virtual table].  
** This structure consists mostly of methods for the module.
**
** ^A virtual table module is created by filling in a persistent
** instance of this structure and passing a pointer to that instance
** to [sqlite3_create_module()] or [sqlite3_create_module_v2()].
** ^The registration remains valid until it is replaced by a different
** module or until the [database connection] closes.  The content
7593
7594
7595
7596
7597
7598
7599
7600






7601
7602
7603
7604
7605
7606
7607
** non-zero.
**
** The [xBestIndex] method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter.  ^If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv.  ^(If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
** virtual table and is not checked again by SQLite.)^






**
** ^The idxNum and idxPtr values are recorded and passed into the
** [xFilter] method.
** ^[sqlite3_free()] is used to free idxPtr if and only if
** needToFreeIdxPtr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in







|
>
>
>
>
>
>







7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804
7805
7806
7807
7808
7809
7810
7811
** non-zero.
**
** The [xBestIndex] method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter.  ^If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv.  ^(If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
** virtual table and might not be checked again by the byte code.)^ ^(The
** aConstraintUsage[].omit flag is an optimization hint. When the omit flag
** is left in its default setting of false, the constraint will always be
** checked separately in byte code.  If the omit flag is change to true, then
** the constraint may or may not be checked in byte code.  In other words,
** when the omit flag is true there is no guarantee that the constraint will
** not be checked again using byte code.)^
**
** ^The idxNum and idxPtr values are recorded and passed into the
** [xFilter] method.
** ^[sqlite3_free()] is used to free idxPtr if and only if
** needToFreeIdxPtr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting 
** to read or write the estimatedRows field are undefined (but are likely 
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for [version 3.9.0] ([dateof:3.9.0]). 
** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/







|







7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
7851
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting 
** to read or write the estimatedRows field are undefined (but are likely 
** to include crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for [version 3.9.0] ([dateof:3.9.0]). 
** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
** these bits.
*/
#define SQLITE_INDEX_SCAN_UNIQUE      1     /* Scan visits at most 1 row */

/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
** These macros defined the allowed values for the
** [sqlite3_index_info].aConstraint[].op field.  Each value represents
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
#define SQLITE_INDEX_CONSTRAINT_EQ         2
#define SQLITE_INDEX_CONSTRAINT_GT         4
#define SQLITE_INDEX_CONSTRAINT_LE         8







|







7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
** these bits.
*/
#define SQLITE_INDEX_SCAN_UNIQUE      1     /* Scan visits at most 1 row */

/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
** These macros define the allowed values for the
** [sqlite3_index_info].aConstraint[].op field.  Each value represents
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
#define SQLITE_INDEX_CONSTRAINT_EQ         2
#define SQLITE_INDEX_CONSTRAINT_GT         4
#define SQLITE_INDEX_CONSTRAINT_LE         8
8295
8296
8297
8298
8299
8300
8301
8302
8303
8304
8305
8306
8307
8308
8309
**   <li>  [sqlite3_mutex_held()] </li>
**   <li>  [sqlite3_mutex_notheld()] </li>
** </ul>)^
**
** The only difference is that the public sqlite3_XXX functions enumerated
** above silently ignore any invocations that pass a NULL pointer instead
** of a valid mutex handle. The implementations of the methods defined
** by this structure are not required to handle this case, the results
** of passing a NULL pointer instead of a valid mutex handle are undefined
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
**
** The xMutexInit() method must be threadsafe.  It must be harmless to
** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd().  Second and subsequent calls to







|







8499
8500
8501
8502
8503
8504
8505
8506
8507
8508
8509
8510
8511
8512
8513
**   <li>  [sqlite3_mutex_held()] </li>
**   <li>  [sqlite3_mutex_notheld()] </li>
** </ul>)^
**
** The only difference is that the public sqlite3_XXX functions enumerated
** above silently ignore any invocations that pass a NULL pointer instead
** of a valid mutex handle. The implementations of the methods defined
** by this structure are not required to handle this case. The results
** of passing a NULL pointer instead of a valid mutex handle are undefined
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
**
** The xMutexInit() method must be threadsafe.  It must be harmless to
** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd().  Second and subsequent calls to
8484
8485
8486
8487
8488
8489
8490
8491
8492
8493
8494
8495
8496
8497
8498
#define SQLITE_TESTCTRL_PRNG_RESET               7  /* NOT USED */
#define SQLITE_TESTCTRL_BITVEC_TEST              8
#define SQLITE_TESTCTRL_FAULT_INSTALL            9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS     10
#define SQLITE_TESTCTRL_PENDING_BYTE            11
#define SQLITE_TESTCTRL_ASSERT                  12
#define SQLITE_TESTCTRL_ALWAYS                  13
#define SQLITE_TESTCTRL_RESERVE                 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS           15
#define SQLITE_TESTCTRL_ISKEYWORD               16  /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS      17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
#define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19







|







8688
8689
8690
8691
8692
8693
8694
8695
8696
8697
8698
8699
8700
8701
8702
#define SQLITE_TESTCTRL_PRNG_RESET               7  /* NOT USED */
#define SQLITE_TESTCTRL_BITVEC_TEST              8
#define SQLITE_TESTCTRL_FAULT_INSTALL            9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS     10
#define SQLITE_TESTCTRL_PENDING_BYTE            11
#define SQLITE_TESTCTRL_ASSERT                  12
#define SQLITE_TESTCTRL_ALWAYS                  13
#define SQLITE_TESTCTRL_RESERVE                 14  /* NOT USED */
#define SQLITE_TESTCTRL_OPTIMIZATIONS           15
#define SQLITE_TESTCTRL_ISKEYWORD               16  /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS      17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
#define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
8768
8769
8770
8771
8772
8773
8774
8775
8776
8777
8778
8779
8780
8781
8782
** returned value includes allocations that overflowed because they
** where too large (they were larger than the "sz" parameter to
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
** no space was left in the page cache.</dd>)^
**
** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
** <dd>This parameter records the largest memory allocation request
** handed to [pagecache memory allocator].  Only the value returned in the
** *pHighwater parameter to [sqlite3_status()] is of interest.  
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>







|







8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982
8983
8984
8985
8986
** returned value includes allocations that overflowed because they
** where too large (they were larger than the "sz" parameter to
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
** no space was left in the page cache.</dd>)^
**
** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
** <dd>This parameter records the largest memory allocation request
** handed to the [pagecache memory allocator].  Only the value returned in the
** *pHighwater parameter to [sqlite3_status()] is of interest.  
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
8844
8845
8846
8847
8848
8849
8850
8851
8852
8853
8854
8855
8856
8857
8858
**
** <dl>
** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
** <dd>This parameter returns the number malloc attempts that were 
** satisfied using lookaside memory. Only the high-water value is meaningful;
** the current value is always zero.)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
** <dd>This parameter returns the number malloc attempts that might have
** been satisfied using lookaside memory but failed due to the amount of







|







9048
9049
9050
9051
9052
9053
9054
9055
9056
9057
9058
9059
9060
9061
9062
**
** <dl>
** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
** <dd>This parameter returns the number of malloc attempts that were 
** satisfied using lookaside memory. Only the high-water value is meaningful;
** the current value is always zero.)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
** <dd>This parameter returns the number malloc attempts that might have
** been satisfied using lookaside memory but failed due to the amount of
8926
8927
8928
8929
8930
8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
**
** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt>
** <dd>This parameter returns the number of dirty cache entries that have
** been written to disk in the middle of a transaction due to the page
** cache overflowing. Transactions are more efficient if they are written
** to disk all at once. When pages spill mid-transaction, that introduces
** additional overhead. This parameter can be used help identify
** inefficiencies that can be resolve by increasing the cache size.
** </dd>
**
** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
** <dd>This parameter returns zero for the current value if and only if
** all foreign key constraints (deferred or immediate) have been
** resolved.)^  ^The highwater mark is always 0.
** </dd>







|







9130
9131
9132
9133
9134
9135
9136
9137
9138
9139
9140
9141
9142
9143
9144
**
** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt>
** <dd>This parameter returns the number of dirty cache entries that have
** been written to disk in the middle of a transaction due to the page
** cache overflowing. Transactions are more efficient if they are written
** to disk all at once. When pages spill mid-transaction, that introduces
** additional overhead. This parameter can be used help identify
** inefficiencies that can be resolved by increasing the cache size.
** </dd>
**
** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
** <dd>This parameter returns zero for the current value if and only if
** all foreign key constraints (deferred or immediate) have been
** resolved.)^  ^The highwater mark is always 0.
** </dd>
9015
9016
9017
9018
9019
9020
9021
9022
9023
9024
9025
9026
9027
9028
9029
** to 2147483647.  The number of virtual machine operations can be 
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
**
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
** <dd>^This is the number of times that the prepare statement has been
** automatically regenerated due to schema changes or change to 
** [bound parameters] that might affect the query plan.
**
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
** <dd>^This is the number of times that the prepared statement has
** been run.  A single "run" for the purposes of this counter is one
** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
** The counter is incremented on the first [sqlite3_step()] call of each







|







9219
9220
9221
9222
9223
9224
9225
9226
9227
9228
9229
9230
9231
9232
9233
** to 2147483647.  The number of virtual machine operations can be 
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
**
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
** <dd>^This is the number of times that the prepare statement has been
** automatically regenerated due to schema changes or changes to 
** [bound parameters] that might affect the query plan.
**
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
** <dd>^This is the number of times that the prepared statement has
** been run.  A single "run" for the purposes of this counter is one
** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
** The counter is incremented on the first [sqlite3_step()] call of each
9186
9187
9188
9189
9190
9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
**                 Otherwise return NULL.
** <tr><td> 2 <td> Make every effort to allocate a new page.  Only return
**                 NULL if allocating a new page is effectively impossible.
** </table>
**
** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  SQLite
** will only use a createFlag of 2 after a prior call with a createFlag of 1
** failed.)^  In between the to xFetch() calls, SQLite may
** attempt to unpin one or more cache pages by spilling the content of
** pinned pages to disk and synching the operating system disk cache.
**
** [[the xUnpin() page cache method]]
** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
** as its second argument.  If the third parameter, discard, is non-zero,
** then the page must be evicted from the cache.







|







9390
9391
9392
9393
9394
9395
9396
9397
9398
9399
9400
9401
9402
9403
9404
**                 Otherwise return NULL.
** <tr><td> 2 <td> Make every effort to allocate a new page.  Only return
**                 NULL if allocating a new page is effectively impossible.
** </table>
**
** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  SQLite
** will only use a createFlag of 2 after a prior call with a createFlag of 1
** failed.)^  In between the xFetch() calls, SQLite may
** attempt to unpin one or more cache pages by spilling the content of
** pinned pages to disk and synching the operating system disk cache.
**
** [[the xUnpin() page cache method]]
** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
** as its second argument.  If the third parameter, discard, is non-zero,
** then the page must be evicted from the cache.
9504
9505
9506
9507
9508
9509
9510
9511
9512
9513
9514
9515
9516
9517
9518
** identity of the database connection (the blocking connection) that
** has locked the required resource is stored internally. ^After an 
** application receives an SQLITE_LOCKED error, it may call the
** sqlite3_unlock_notify() method with the blocked connection handle as 
** the first argument to register for a callback that will be invoked
** when the blocking connections current transaction is concluded. ^The
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
** call that concludes the blocking connections transaction.
**
** ^(If sqlite3_unlock_notify() is called in a multi-threaded application,
** there is a chance that the blocking connection will have already
** concluded its transaction by the time sqlite3_unlock_notify() is invoked.
** If this happens, then the specified callback is invoked immediately,
** from within the call to sqlite3_unlock_notify().)^
**







|







9708
9709
9710
9711
9712
9713
9714
9715
9716
9717
9718
9719
9720
9721
9722
** identity of the database connection (the blocking connection) that
** has locked the required resource is stored internally. ^After an 
** application receives an SQLITE_LOCKED error, it may call the
** sqlite3_unlock_notify() method with the blocked connection handle as 
** the first argument to register for a callback that will be invoked
** when the blocking connections current transaction is concluded. ^The
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
** call that concludes the blocking connection's transaction.
**
** ^(If sqlite3_unlock_notify() is called in a multi-threaded application,
** there is a chance that the blocking connection will have already
** concluded its transaction by the time sqlite3_unlock_notify() is invoked.
** If this happens, then the specified callback is invoked immediately,
** from within the call to sqlite3_unlock_notify().)^
**
9542
9543
9544
9545
9546
9547
9548
9549
9550
9551
9552
9553
9554
9555
9556
** When an unlock-notify callback is registered, the application provides a 
** single void* pointer that is passed to the callback when it is invoked.
** However, the signature of the callback function allows SQLite to pass
** it an array of void* context pointers. The first argument passed to
** an unlock-notify callback is a pointer to an array of void* pointers,
** and the second is the number of entries in the array.
**
** When a blocking connections transaction is concluded, there may be
** more than one blocked connection that has registered for an unlock-notify
** callback. ^If two or more such blocked connections have specified the
** same callback function, then instead of invoking the callback function
** multiple times, it is invoked once with the set of void* context pointers
** specified by the blocked connections bundled together into an array.
** This gives the application an opportunity to prioritize any actions 
** related to the set of unblocked database connections.







|







9746
9747
9748
9749
9750
9751
9752
9753
9754
9755
9756
9757
9758
9759
9760
** When an unlock-notify callback is registered, the application provides a 
** single void* pointer that is passed to the callback when it is invoked.
** However, the signature of the callback function allows SQLite to pass
** it an array of void* context pointers. The first argument passed to
** an unlock-notify callback is a pointer to an array of void* pointers,
** and the second is the number of entries in the array.
**
** When a blocking connection's transaction is concluded, there may be
** more than one blocked connection that has registered for an unlock-notify
** callback. ^If two or more such blocked connections have specified the
** same callback function, then instead of invoking the callback function
** multiple times, it is invoked once with the set of void* context pointers
** specified by the blocked connections bundled together into an array.
** This gives the application an opportunity to prioritize any actions 
** related to the set of unblocked database connections.
9890
9891
9892
9893
9894
9895
9896
9897
9898




9899
9900
9901
9902
9903
9904


9905
9906
9907
9908
9909
9910
9911
9912
9913
9914
9915
9916
9917
9918
9919
** This function may be called by either the [xConnect] or [xCreate] method
** of a [virtual table] implementation to configure
** various facets of the virtual table interface.
**
** If this interface is invoked outside the context of an xConnect or
** xCreate virtual table method then the behavior is undefined.
**
** At present, there is only one option that may be configured using
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].)  Further options




** may be added in the future.
*/
SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);

/*
** CAPI3REF: Virtual Table Configuration Options


**
** These macros define the various options to the
** [sqlite3_vtab_config()] interface that [virtual table] implementations
** can use to customize and optimize their behavior.
**
** <dl>
** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]]
** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
** where X is an integer.  If X is zero, then the [virtual table] whose
** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not
** support constraints.  In this configuration (which is the default) if
** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
** statement is rolled back as if [ON CONFLICT | OR ABORT] had been







|
|
>
>
>
>
|





>
>







|







10094
10095
10096
10097
10098
10099
10100
10101
10102
10103
10104
10105
10106
10107
10108
10109
10110
10111
10112
10113
10114
10115
10116
10117
10118
10119
10120
10121
10122
10123
10124
10125
10126
10127
10128
10129
** This function may be called by either the [xConnect] or [xCreate] method
** of a [virtual table] implementation to configure
** various facets of the virtual table interface.
**
** If this interface is invoked outside the context of an xConnect or
** xCreate virtual table method then the behavior is undefined.
**
** In the call sqlite3_vtab_config(D,C,...) the D parameter is the
** [database connection] in which the virtual table is being created and
** which is passed in as the first argument to the [xConnect] or [xCreate]
** method that is invoking sqlite3_vtab_config().  The C parameter is one
** of the [virtual table configuration options].  The presence and meaning
** of parameters after C depend on which [virtual table configuration option]
** is used.
*/
SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);

/*
** CAPI3REF: Virtual Table Configuration Options
** KEYWORDS: {virtual table configuration options} 
** KEYWORDS: {virtual table configuration option}
**
** These macros define the various options to the
** [sqlite3_vtab_config()] interface that [virtual table] implementations
** can use to customize and optimize their behavior.
**
** <dl>
** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]]
** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
** where X is an integer.  If X is zero, then the [virtual table] whose
** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not
** support constraints.  In this configuration (which is the default) if
** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
9934
9935
9936
9937
9938
9939
9940




















9941
9942
9943


9944
9945
9946
9947
9948
9949
9950
** must do so within the [xUpdate] method. If a call to the 
** [sqlite3_vtab_on_conflict()] function indicates that the current ON 
** CONFLICT policy is REPLACE, the virtual table implementation should 
** silently replace the appropriate rows within the xUpdate callback and
** return SQLITE_OK. Or, if this is not possible, it may return
** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT 
** constraint handling.




















** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1



/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
**
** This function may only be called from within a call to the [xUpdate] method
** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],







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



>
>







10144
10145
10146
10147
10148
10149
10150
10151
10152
10153
10154
10155
10156
10157
10158
10159
10160
10161
10162
10163
10164
10165
10166
10167
10168
10169
10170
10171
10172
10173
10174
10175
10176
10177
10178
10179
10180
10181
10182
** must do so within the [xUpdate] method. If a call to the 
** [sqlite3_vtab_on_conflict()] function indicates that the current ON 
** CONFLICT policy is REPLACE, the virtual table implementation should 
** silently replace the appropriate rows within the xUpdate callback and
** return SQLITE_OK. Or, if this is not possible, it may return
** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT 
** constraint handling.
** </dd>
**
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
**
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
** identify that virtual table as being safe to use from within triggers
** and views.  Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker.  Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS          2
#define SQLITE_VTAB_DIRECTONLY         3

/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
**
** This function may only be called from within a call to the [xUpdate] method
** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
10016
10017
10018
10019
10020
10021
10022
10023
10024
10025
10026
10027
10028
10029
10030
10031
10032
10033
10034
10035
10036
10037
10038
10039
10040
10041
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051
10052
10053
10054
10055
10056
**
** When the value returned to V is a string, space to hold that string is
** managed by the prepared statement S and will be automatically freed when
** S is finalized.
**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
** set to the total number of times that the X-th loop has run.</dd>
**
** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
** to the total number of rows examined by all iterations of the X-th loop.</dd>
**
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
** <dd>^The "double" variable pointed to by the T parameter will be set to the
** query planner's estimate for the average number of rows output from each
** iteration of the X-th loop.  If the query planner's estimates was accurate,
** then this value will approximate the quotient NVISIT/NLOOP and the
** product of this value for all prior loops with the same SELECTID will
** be the NLOOP value for the current loop.
**
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
** <dd>^The "const char *" variable pointed to by the T parameter will be set
** to a zero-terminated UTF-8 string containing the name of the index or table
** used for the X-th loop.
**
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
** <dd>^The "const char *" variable pointed to by the T parameter will be set
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
** <dd>^The "int" variable pointed to by the T parameter will be set to the
** "select-id" for the X-th loop.  The select-id identifies which query or
** subquery the loop is part of.  The main query has a select-id of zero.
** The select-id is the same value as is output in the first column
** of an [EXPLAIN QUERY PLAN] query.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP    0







|



|



|







|




|




|







10248
10249
10250
10251
10252
10253
10254
10255
10256
10257
10258
10259
10260
10261
10262
10263
10264
10265
10266
10267
10268
10269
10270
10271
10272
10273
10274
10275
10276
10277
10278
10279
10280
10281
10282
10283
10284
10285
10286
10287
10288
**
** When the value returned to V is a string, space to hold that string is
** managed by the prepared statement S and will be automatically freed when
** S is finalized.
**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
** set to the total number of times that the X-th loop has run.</dd>
**
** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be set
** to the total number of rows examined by all iterations of the X-th loop.</dd>
**
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
** <dd>^The "double" variable pointed to by the V parameter will be set to the
** query planner's estimate for the average number of rows output from each
** iteration of the X-th loop.  If the query planner's estimates was accurate,
** then this value will approximate the quotient NVISIT/NLOOP and the
** product of this value for all prior loops with the same SELECTID will
** be the NLOOP value for the current loop.
**
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the name of the index or table
** used for the X-th loop.
**
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
** <dd>^The "int" variable pointed to by the V parameter will be set to the
** "select-id" for the X-th loop.  The select-id identifies which query or
** subquery the loop is part of.  The main query has a select-id of zero.
** The select-id is the same value as is output in the first column
** of an [EXPLAIN QUERY PLAN] query.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP    0
10897
10898
10899
10900
10901
10902
10903
10904
10905
10906
10907
10908
10909
10910
10911
/*
** CAPI3REF: Set a table filter on a Session Object.
** METHOD: sqlite3_session
**
** The second argument (xFilter) is the "filter callback". For changes to rows 
** in tables that are not attached to the Session object, the filter is called
** to determine whether changes to the table's rows should be tracked or not. 
** If xFilter returns 0, changes is not tracked. Note that once a table is 
** attached, xFilter will not be called again.
*/
SQLITE_API void sqlite3session_table_filter(
  sqlite3_session *pSession,      /* Session object */
  int(*xFilter)(
    void *pCtx,                   /* Copy of third arg to _filter_table() */
    const char *zTab              /* Table name */







|







11129
11130
11131
11132
11133
11134
11135
11136
11137
11138
11139
11140
11141
11142
11143
/*
** CAPI3REF: Set a table filter on a Session Object.
** METHOD: sqlite3_session
**
** The second argument (xFilter) is the "filter callback". For changes to rows 
** in tables that are not attached to the Session object, the filter is called
** to determine whether changes to the table's rows should be tracked or not. 
** If xFilter returns 0, changes are not tracked. Note that once a table is 
** attached, xFilter will not be called again.
*/
SQLITE_API void sqlite3session_table_filter(
  sqlite3_session *pSession,      /* Session object */
  int(*xFilter)(
    void *pCtx,                   /* Copy of third arg to _filter_table() */
    const char *zTab              /* Table name */
11071
11072
11073
11074
11075
11076
11077
11078
11079
11080
11081
11082
11083
11084
11085
** using [sqlite3session_changeset()], then after applying that changeset to 
** database zFrom the contents of the two compatible tables would be 
** identical.
**
** It an error if database zFrom does not exist or does not contain the
** required compatible table.
**
** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
** may be set to point to a buffer containing an English language error 
** message. It is the responsibility of the caller to free this buffer using
** sqlite3_free().
*/
SQLITE_API int sqlite3session_diff(
  sqlite3_session *pSession,







|







11303
11304
11305
11306
11307
11308
11309
11310
11311
11312
11313
11314
11315
11316
11317
** using [sqlite3session_changeset()], then after applying that changeset to 
** database zFrom the contents of the two compatible tables would be 
** identical.
**
** It an error if database zFrom does not exist or does not contain the
** required compatible table.
**
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
** may be set to point to a buffer containing an English language error 
** message. It is the responsibility of the caller to free this buffer using
** sqlite3_free().
*/
SQLITE_API int sqlite3session_diff(
  sqlite3_session *pSession,
11208
11209
11210
11211
11212
11213
11214
11215
11216
11217
11218
11219
11220
11221
11222
#define SQLITE_CHANGESETSTART_INVERT        0x0002


/*
** CAPI3REF: Advance A Changeset Iterator
** METHOD: sqlite3_changeset_iter
**
** This function may only be used with iterators created by function
** [sqlite3changeset_start()]. If it is called on an iterator passed to
** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
** is returned and the call has no effect.
**
** Immediately after an iterator is created by sqlite3changeset_start(), it
** does not point to any change in the changeset. Assuming the changeset
** is not empty, the first call to this function advances the iterator to







|







11440
11441
11442
11443
11444
11445
11446
11447
11448
11449
11450
11451
11452
11453
11454
#define SQLITE_CHANGESETSTART_INVERT        0x0002


/*
** CAPI3REF: Advance A Changeset Iterator
** METHOD: sqlite3_changeset_iter
**
** This function may only be used with iterators created by the function
** [sqlite3changeset_start()]. If it is called on an iterator passed to
** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
** is returned and the call has no effect.
**
** Immediately after an iterator is created by sqlite3changeset_start(), it
** does not point to any change in the changeset. Assuming the changeset
** is not empty, the first call to this function advances the iterator to
11624
11625
11626
11627
11628
11629
11630
11631
11632
11633
11634
11635
11636
11637
11638
11639
**
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
** case, this function fails with SQLITE_SCHEMA. If the input changeset
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
** returned. Or, if an out-of-memory condition occurs during processing, this
** function returns SQLITE_NOMEM. In all cases, if an error occurs the
** final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);

/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup







|
|







11856
11857
11858
11859
11860
11861
11862
11863
11864
11865
11866
11867
11868
11869
11870
11871
**
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
** case, this function fails with SQLITE_SCHEMA. If the input changeset
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
** returned. Or, if an out-of-memory condition occurs during processing, this
** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
** of the final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);

/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
11800
11801
11802
11803
11804
11805
11806
11807
11808
11809
11810
11811
11812
11813
11814
**   This includes the case where the UPDATE operation is attempted after 
**   an earlier call to the conflict handler function returned
**   [SQLITE_CHANGESET_REPLACE].  
** </dl>
**
** It is safe to execute SQL statements, including those that write to the
** table that the callback related to, from within the xConflict callback.
** This can be used to further customize the applications conflict
** resolution strategy.
**
** All changes made by these functions are enclosed in a savepoint transaction.
** If any other error (aside from a constraint failure when attempting to
** write to the target database) occurs, then the savepoint transaction is
** rolled back, restoring the target database to its original state, and an 
** SQLite error code returned.







|







12032
12033
12034
12035
12036
12037
12038
12039
12040
12041
12042
12043
12044
12045
12046
**   This includes the case where the UPDATE operation is attempted after 
**   an earlier call to the conflict handler function returned
**   [SQLITE_CHANGESET_REPLACE].  
** </dl>
**
** It is safe to execute SQL statements, including those that write to the
** table that the callback related to, from within the xConflict callback.
** This can be used to further customize the application's conflict
** resolution strategy.
**
** All changes made by these functions are enclosed in a savepoint transaction.
** If any other error (aside from a constraint failure when attempting to
** write to the target database) occurs, then the savepoint transaction is
** rolled back, restoring the target database to its original state, and an 
** SQLite error code returned.
12110
12111
12112
12113
12114
12115
12116
12117
12118
12119
12120
12121
12122
12123
12124

/*
** CAPI3REF: Rebase a changeset
** EXPERIMENTAL
**
** Argument pIn must point to a buffer containing a changeset nIn bytes
** in size. This function allocates and populates a buffer with a copy
** of the changeset rebased rebased according to the configuration of the
** rebaser object passed as the first argument. If successful, (*ppOut)
** is set to point to the new buffer containing the rebased changeset and 
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
** responsibility of the caller to eventually free the new buffer using
** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
** are set to zero and an SQLite error code returned.
*/







|







12342
12343
12344
12345
12346
12347
12348
12349
12350
12351
12352
12353
12354
12355
12356

/*
** CAPI3REF: Rebase a changeset
** EXPERIMENTAL
**
** Argument pIn must point to a buffer containing a changeset nIn bytes
** in size. This function allocates and populates a buffer with a copy
** of the changeset rebased according to the configuration of the
** rebaser object passed as the first argument. If successful, (*ppOut)
** is set to point to the new buffer containing the rebased changeset and 
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
** responsibility of the caller to eventually free the new buffer using
** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
** are set to zero and an SQLite error code returned.
*/
12518
12519
12520
12521
12522
12523
12524
12525
12526
12527
12528
12529
12530
12531
12532
**   If the query runs to completion without incident, SQLITE_OK is returned.
**   Or, if some error occurs before the query completes or is aborted by
**   the callback, an SQLite error code is returned.
**
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
**   Save the pointer passed as the second argument as the extension functions 
**   "auxiliary data". The pointer may then be retrieved by the current or any
**   future invocation of the same fts5 extension function made as part of
**   the same MATCH query using the xGetAuxdata() API.
**
**   Each extension function is allocated a single auxiliary data slot for
**   each FTS query (MATCH expression). If the extension function is invoked 
**   more than once for a single FTS query, then all invocations share a 







|







12750
12751
12752
12753
12754
12755
12756
12757
12758
12759
12760
12761
12762
12763
12764
**   If the query runs to completion without incident, SQLITE_OK is returned.
**   Or, if some error occurs before the query completes or is aborted by
**   the callback, an SQLite error code is returned.
**
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
**   Save the pointer passed as the second argument as the extension function's 
**   "auxiliary data". The pointer may then be retrieved by the current or any
**   future invocation of the same fts5 extension function made as part of
**   the same MATCH query using the xGetAuxdata() API.
**
**   Each extension function is allocated a single auxiliary data slot for
**   each FTS query (MATCH expression). If the extension function is invoked 
**   more than once for a single FTS query, then all invocations share a 
12760
12761
12762
12763
12764
12765
12766
12767
12768
12769
12770
12771
12772
12773
12774
12775
**   of "first place" within the document set, but not alternative forms
**   such as "1st place". In some applications, it would be better to match
**   all instances of "first place" or "1st place" regardless of which form
**   the user specified in the MATCH query text.
**
**   There are several ways to approach this in FTS5:
**
**   <ol><li> By mapping all synonyms to a single token. In this case, the 
**            In the above example, this means that the tokenizer returns the
**            same token for inputs "first" and "1st". Say that token is in
**            fact "first", so that when the user inserts the document "I won
**            1st place" entries are added to the index for tokens "i", "won",
**            "first" and "place". If the user then queries for '1st + place',
**            the tokenizer substitutes "first" for "1st" and the query works
**            as expected.
**







|
|







12992
12993
12994
12995
12996
12997
12998
12999
13000
13001
13002
13003
13004
13005
13006
13007
**   of "first place" within the document set, but not alternative forms
**   such as "1st place". In some applications, it would be better to match
**   all instances of "first place" or "1st place" regardless of which form
**   the user specified in the MATCH query text.
**
**   There are several ways to approach this in FTS5:
**
**   <ol><li> By mapping all synonyms to a single token. In this case, using
**            the above example, this means that the tokenizer returns the
**            same token for inputs "first" and "1st". Say that token is in
**            fact "first", so that when the user inserts the document "I won
**            1st place" entries are added to the index for tokens "i", "won",
**            "first" and "place". If the user then queries for '1st + place',
**            the tokenizer substitutes "first" for "1st" and the query works
**            as expected.
**
13082
13083
13084
13085
13086
13087
13088



13089
13090
13091
13092
13093
13094
13095
13096
13097
13098
#ifndef SQLITE_MAX_ATTACHED
# define SQLITE_MAX_ATTACHED 10
#endif


/*
** The maximum value of a ?nnn wildcard that the parser will accept.



*/
#ifndef SQLITE_MAX_VARIABLE_NUMBER
# define SQLITE_MAX_VARIABLE_NUMBER 999
#endif

/* Maximum page size.  The upper bound on this value is 65536.  This a limit
** imposed by the use of 16-bit offsets within each page.
**
** Earlier versions of SQLite allowed the user to change this value at
** compile time. This is no longer permitted, on the grounds that it creates







>
>
>


|







13314
13315
13316
13317
13318
13319
13320
13321
13322
13323
13324
13325
13326
13327
13328
13329
13330
13331
13332
13333
#ifndef SQLITE_MAX_ATTACHED
# define SQLITE_MAX_ATTACHED 10
#endif


/*
** The maximum value of a ?nnn wildcard that the parser will accept.
** If the value exceeds 32767 then extra space is required for the Expr
** structure.  But otherwise, we believe that the number can be as large
** as a signed 32-bit integer can hold.
*/
#ifndef SQLITE_MAX_VARIABLE_NUMBER
# define SQLITE_MAX_VARIABLE_NUMBER 32766
#endif

/* Maximum page size.  The upper bound on this value is 65536.  This a limit
** imposed by the use of 16-bit offsets within each page.
**
** Earlier versions of SQLite allowed the user to change this value at
** compile time. This is no longer permitted, on the grounds that it creates
13173
13174
13175
13176
13177
13178
13179















13180
13181
13182
13183
13184
13185
13186
#pragma warn -rch /* unreachable code */
#pragma warn -ccc /* Condition is always true or false */
#pragma warn -aus /* Assigned value is never used */
#pragma warn -csu /* Comparing signed and unsigned */
#pragma warn -spa /* Suspicious pointer arithmetic */
#endif
















/*
** Include standard header files as necessary
*/
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H







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







13408
13409
13410
13411
13412
13413
13414
13415
13416
13417
13418
13419
13420
13421
13422
13423
13424
13425
13426
13427
13428
13429
13430
13431
13432
13433
13434
13435
13436
#pragma warn -rch /* unreachable code */
#pragma warn -ccc /* Condition is always true or false */
#pragma warn -aus /* Assigned value is never used */
#pragma warn -csu /* Comparing signed and unsigned */
#pragma warn -spa /* Suspicious pointer arithmetic */
#endif

/*
** WAL mode depends on atomic aligned 32-bit loads and stores in a few
** places.  The following macros try to make this explicit.
*/
#ifndef __has_feature
# define __has_feature(x) 0       /* compatibility with non-clang compilers */
#endif
#if GCC_VERSION>=4007000 || __has_feature(c_atomic)
# define AtomicLoad(PTR)       __atomic_load_n((PTR),__ATOMIC_RELAXED)
# define AtomicStore(PTR,VAL)  __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
#else
# define AtomicLoad(PTR)       (*(PTR))
# define AtomicStore(PTR,VAL)  (*(PTR) = (VAL))
#endif

/*
** Include standard header files as necessary
*/
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
13433
13434
13435
13436
13437
13438
13439




















13440
13441
13442
13443
13444
13445
13446
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)
# define NEVER(X)       (X)
#endif





















/*
** Some conditionals are optimizations only.  In other words, if the
** conditionals are replaced with a constant 1 (true) or 0 (false) then
** the correct answer is still obtained, though perhaps not as quickly.
**
** The following macros mark these optimizations conditionals.
*/







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







13683
13684
13685
13686
13687
13688
13689
13690
13691
13692
13693
13694
13695
13696
13697
13698
13699
13700
13701
13702
13703
13704
13705
13706
13707
13708
13709
13710
13711
13712
13713
13714
13715
13716
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)
# define NEVER(X)       (X)
#endif

/*
** The harmless(X) macro indicates that expression X is usually false
** but can be true without causing any problems, but we don't know of
** any way to cause X to be true.
**
** In debugging and testing builds, this macro will abort if X is ever
** true.  In this way, developers are alerted to a possible test case
** that causes X to be true.  If a harmless macro ever fails, that is
** an opportunity to change the macro into a testcase() and add a new
** test case to the test suite.
**
** For normal production builds, harmless(X) is a no-op, since it does
** not matter whether expression X is true or false.
*/
#ifdef SQLITE_DEBUG
# define harmless(X)  assert(!(X));
#else
# define harmless(X)
#endif

/*
** Some conditionals are optimizations only.  In other words, if the
** conditionals are replaced with a constant 1 (true) or 0 (false) then
** the correct answer is still obtained, though perhaps not as quickly.
**
** The following macros mark these optimizations conditionals.
*/
14393
14394
14395
14396
14397
14398
14399

14400
14401
14402
14403
14404
14405
14406
*/
#define BMS  ((int)(sizeof(Bitmask)*8))

/*
** A bit in a Bitmask
*/
#define MASKBIT(n)   (((Bitmask)1)<<(n))

#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define ALLBITS      ((Bitmask)-1)

/* A VList object records a mapping between parameters/variables/wildcards
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
** variable number associated with that parameter.  See the format description
** on the sqlite3VListAdd() routine for more information.  A VList is really







>







14663
14664
14665
14666
14667
14668
14669
14670
14671
14672
14673
14674
14675
14676
14677
*/
#define BMS  ((int)(sizeof(Bitmask)*8))

/*
** A bit in a Bitmask
*/
#define MASKBIT(n)   (((Bitmask)1)<<(n))
#define MASKBIT64(n) (((u64)1)<<(n))
#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define ALLBITS      ((Bitmask)-1)

/* A VList object records a mapping between parameters/variables/wildcards
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
** variable number associated with that parameter.  See the format description
** on the sqlite3VListAdd() routine for more information.  A VList is really
14487
14488
14489
14490
14491
14492
14493
14494
14495
14496
14497
14498
14499
14500
14501
#endif
SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree*);
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int,int*);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);







|







14758
14759
14760
14761
14762
14763
14764
14765
14766
14767
14768
14769
14770
14771
14772
#endif
SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree*);
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int,int*);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
14719
14720
14721
14722
14723
14724
14725


14726
14727
14728
14729
14730
14731
14732
                       int flags, int seekResult);
SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags);
SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags);
SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);


#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*);
#endif
SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);







>
>







14990
14991
14992
14993
14994
14995
14996
14997
14998
14999
15000
15001
15002
15003
15004
15005
                       int flags, int seekResult);
SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags);
SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags);
SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor*);
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*);
#endif
SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
15005
15006
15007
15008
15009
15010
15011

15012
15013
15014
15015
15016
15017
15018
15019
15020
15021
15022
15023
15024
15025
15026
15027
15028
15029
15030

15031
15032
15033
15034
15035
15036
15037
15038
15039
15040
15041
15042
15043
15044

15045
15046
15047
15048
15049
15050
15051
15052
15053
15054
15055
15056
15057
15058
15059
15060
15061
15062
15063
15064
15065
15066
15067
15068
15069
15070
15071
15072
15073
15074
15075
15076
15077
15078
15079
15080
15081
15082
15083
15084
15085
15086
15087
15088
15089
15090
15091
15092
15093
15094
15095
15096
15097
15098

15099
15100
15101

15102
15103
15104
15105
15106
15107
15108
15109
15110
15111
15112
15113
15114
15115
15116

15117
15118
15119

15120
15121
15122
15123
15124
15125
15126
15127
15128
15129
15130
15131
15132
15133
15134
15135
15136


15137
15138
15139
15140
15141
15142


15143
15144
15145
15146
15147
15148
15149
15150
15151
15152
15153

15154
15155
15156
15157
15158
15159
15160
15161
15162
15163
15164
15165
15166
15167
15168
15169
15170
15171
15172
15173
15174
15175
15176
15177
15178
15179
15180
15181
15182
15183
15184
15185
15186
15187
15188
15189
15190

15191
15192
15193
15194
15195
15196
15197
15198
15199
15200
15201
15202
15203
15204
15205
#define OP_Not            19 /* same as TK_NOT, synopsis: r[P2]= !r[P1]    */
#define OP_IfNot          20 /* jump                                       */
#define OP_IfNullRow      21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
#define OP_SeekLT         22 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekLE         23 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekGE         24 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekGT         25 /* jump, synopsis: key=r[P3@P4]               */

#define OP_IfNoHope       26 /* jump, synopsis: key=r[P3@P4]               */
#define OP_NoConflict     27 /* jump, synopsis: key=r[P3@P4]               */
#define OP_NotFound       28 /* jump, synopsis: key=r[P3@P4]               */
#define OP_Found          29 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekRowid      30 /* jump, synopsis: intkey=r[P3]               */
#define OP_NotExists      31 /* jump, synopsis: intkey=r[P3]               */
#define OP_Last           32 /* jump                                       */
#define OP_IfSmaller      33 /* jump                                       */
#define OP_SorterSort     34 /* jump                                       */
#define OP_Sort           35 /* jump                                       */
#define OP_Rewind         36 /* jump                                       */
#define OP_IdxLE          37 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxGT          38 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxLT          39 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxGE          40 /* jump, synopsis: key=r[P3@P4]               */
#define OP_RowSetRead     41 /* jump, synopsis: r[P3]=rowset(P1)           */
#define OP_RowSetTest     42 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
#define OP_Or             43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And            44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */

#define OP_Program        45 /* jump                                       */
#define OP_FkIfZero       46 /* jump, synopsis: if fkctr[P1]==0 goto P2    */
#define OP_IfPos          47 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
#define OP_IfNotZero      48 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
#define OP_DecrJumpZero   49 /* jump, synopsis: if (--r[P1])==0 goto P2    */
#define OP_IsNull         50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull        51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne             52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
#define OP_Eq             53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
#define OP_Gt             54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
#define OP_Le             55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
#define OP_Lt             56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge             57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseNotEq      58 /* jump, same as TK_ESCAPE                    */

#define OP_IncrVacuum     59 /* jump                                       */
#define OP_VNext          60 /* jump                                       */
#define OP_Init           61 /* jump, synopsis: Start at P2                */
#define OP_PureFunc       62 /* synopsis: r[P3]=func(r[P2@P5])             */
#define OP_Function       63 /* synopsis: r[P3]=func(r[P2@P5])             */
#define OP_Return         64
#define OP_EndCoroutine   65
#define OP_HaltIfNull     66 /* synopsis: if r[P3]=null halt               */
#define OP_Halt           67
#define OP_Integer        68 /* synopsis: r[P2]=P1                         */
#define OP_Int64          69 /* synopsis: r[P2]=P4                         */
#define OP_String         70 /* synopsis: r[P2]='P4' (len=P1)              */
#define OP_Null           71 /* synopsis: r[P2..P3]=NULL                   */
#define OP_SoftNull       72 /* synopsis: r[P1]=NULL                       */
#define OP_Blob           73 /* synopsis: r[P2]=P4 (len=P1)                */
#define OP_Variable       74 /* synopsis: r[P2]=parameter(P1,P4)           */
#define OP_Move           75 /* synopsis: r[P2@P3]=r[P1@P3]                */
#define OP_Copy           76 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
#define OP_SCopy          77 /* synopsis: r[P2]=r[P1]                      */
#define OP_IntCopy        78 /* synopsis: r[P2]=r[P1]                      */
#define OP_ResultRow      79 /* synopsis: output=r[P1@P2]                  */
#define OP_CollSeq        80
#define OP_AddImm         81 /* synopsis: r[P1]=r[P1]+P2                   */
#define OP_RealAffinity   82
#define OP_Cast           83 /* synopsis: affinity(r[P1])                  */
#define OP_Permutation    84
#define OP_Compare        85 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
#define OP_IsTrue         86 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
#define OP_Offset         87 /* synopsis: r[P3] = sqlite_offset(P1)        */
#define OP_Column         88 /* synopsis: r[P3]=PX                         */
#define OP_Affinity       89 /* synopsis: affinity(r[P1@P2])               */
#define OP_MakeRecord     90 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
#define OP_Count          91 /* synopsis: r[P2]=count()                    */
#define OP_ReadCookie     92
#define OP_SetCookie      93
#define OP_ReopenIdx      94 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenRead       95 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenWrite      96 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenDup        97
#define OP_OpenAutoindex  98 /* synopsis: nColumn=P2                       */
#define OP_OpenEphemeral  99 /* synopsis: nColumn=P2                       */
#define OP_SorterOpen    100
#define OP_BitAnd        101 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr         102 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft     103 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
#define OP_ShiftRight    104 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
#define OP_Add           105 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
#define OP_Subtract      106 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
#define OP_Multiply      107 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
#define OP_Divide        108 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
#define OP_Remainder     109 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
#define OP_Concat        110 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_SequenceTest  111 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
#define OP_BitNot        112 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */

#define OP_OpenPseudo    113 /* synopsis: P3 columns in r[P2]              */
#define OP_Close         114
#define OP_String8       115 /* same as TK_STRING, synopsis: r[P2]='P4'    */

#define OP_ColumnsUsed   116
#define OP_SeekHit       117 /* synopsis: seekHit=P2                       */
#define OP_Sequence      118 /* synopsis: r[P2]=cursor[P1].ctr++           */
#define OP_NewRowid      119 /* synopsis: r[P2]=rowid                      */
#define OP_Insert        120 /* synopsis: intkey=r[P3] data=r[P2]          */
#define OP_Delete        121
#define OP_ResetCount    122
#define OP_SorterCompare 123 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
#define OP_SorterData    124 /* synopsis: r[P2]=data                       */
#define OP_RowData       125 /* synopsis: r[P2]=data                       */
#define OP_Rowid         126 /* synopsis: r[P2]=rowid                      */
#define OP_NullRow       127
#define OP_SeekEnd       128
#define OP_SorterInsert  129 /* synopsis: key=r[P2]                        */
#define OP_IdxInsert     130 /* synopsis: key=r[P2]                        */

#define OP_IdxDelete     131 /* synopsis: key=r[P2@P3]                     */
#define OP_DeferredSeek  132 /* synopsis: Move P3 to P1.rowid if needed    */
#define OP_IdxRowid      133 /* synopsis: r[P2]=rowid                      */

#define OP_Destroy       134
#define OP_Clear         135
#define OP_ResetSorter   136
#define OP_CreateBtree   137 /* synopsis: r[P2]=root iDb=P1 flags=P3       */
#define OP_SqlExec       138
#define OP_ParseSchema   139
#define OP_LoadAnalysis  140
#define OP_DropTable     141
#define OP_DropIndex     142
#define OP_DropTrigger   143
#define OP_IntegrityCk   144
#define OP_RowSetAdd     145 /* synopsis: rowset(P1)=r[P2]                 */
#define OP_Param         146
#define OP_FkCounter     147 /* synopsis: fkctr[P1]+=P2                    */
#define OP_MemMax        148 /* synopsis: r[P1]=max(r[P1],r[P2])           */
#define OP_OffsetLimit   149 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
#define OP_Real          150 /* same as TK_FLOAT, synopsis: r[P2]=P4       */


#define OP_AggInverse    151 /* synopsis: accum=r[P3] inverse(r[P2@P5])    */
#define OP_AggStep       152 /* synopsis: accum=r[P3] step(r[P2@P5])       */
#define OP_AggStep1      153 /* synopsis: accum=r[P3] step(r[P2@P5])       */
#define OP_AggValue      154 /* synopsis: r[P3]=value N=P2                 */
#define OP_AggFinal      155 /* synopsis: accum=r[P1] N=P2                 */
#define OP_Expire        156


#define OP_TableLock     157 /* synopsis: iDb=P1 root=P2 write=P3          */
#define OP_VBegin        158
#define OP_VCreate       159
#define OP_VDestroy      160
#define OP_VOpen         161
#define OP_VColumn       162 /* synopsis: r[P3]=vcolumn(P2)                */
#define OP_VRename       163
#define OP_Pagecount     164
#define OP_MaxPgcnt      165
#define OP_Trace         166
#define OP_CursorHint    167

#define OP_Noop          168
#define OP_Explain       169
#define OP_Abortable     170

/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
*/
#define OPFLG_JUMP        0x01  /* jump:  P2 holds jmp target */
#define OPFLG_IN1         0x02  /* in1:   P1 is an input */
#define OPFLG_IN2         0x04  /* in2:   P2 is an input */
#define OPFLG_IN3         0x08  /* in3:   P3 is an input */
#define OPFLG_OUT2        0x10  /* out2:  P2 is an output */
#define OPFLG_OUT3        0x20  /* out3:  P3 is an output */
#define OPFLG_INITIALIZER {\
/*   0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\
/*   8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\
/*  16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\
/*  24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
/*  32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
/*  40 */ 0x01, 0x23, 0x0b, 0x26, 0x26, 0x01, 0x01, 0x03,\
/*  48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
/*  56 */ 0x0b, 0x0b, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,\
/*  64 */ 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10,\
/*  72 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,\
/*  80 */ 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x12, 0x20,\
/*  88 */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\
/*  96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
/* 112 */ 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10,\
/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\
/* 128 */ 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x10, 0x00,\
/* 136 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 144 */ 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a, 0x10, 0x00,\
/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
/* 168 */ 0x00, 0x00, 0x00,}


/* The sqlite3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode.  The smaller the maximum
** JUMP opcode the better, so the mkopcodeh.tcl script that
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
#define SQLITE_MX_JUMP_OPCODE  61  /* Maximum JUMP opcode */

/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/

/*
** Additional non-public SQLITE_PREPARE_* flags
*/







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


>
|
|
|
|
<









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










|

>
|
<

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

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

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















|
|
|

|
|
|
|
|


|
|
|
|
|
|
|
|
>







|







15278
15279
15280
15281
15282
15283
15284
15285
15286
15287
15288
15289
15290
15291
15292
15293
15294
15295
15296
15297
15298
15299
15300
15301

15302
15303
15304
15305
15306
15307
15308

15309
15310
15311
15312
15313
15314
15315
15316
15317
15318
15319
15320
15321
15322
15323
15324
15325
15326
15327
15328
15329
15330
15331
15332
15333
15334
15335
15336
15337
15338
15339
15340
15341
15342
15343
15344
15345
15346
15347
15348
15349
15350
15351
15352
15353
15354
15355
15356
15357
15358
15359

15360
15361
15362
15363
15364
15365
15366
15367
15368
15369
15370
15371
15372
15373

15374
15375
15376
15377
15378
15379
15380
15381
15382
15383
15384
15385
15386
15387
15388

15389
15390
15391
15392
15393
15394
15395
15396
15397
15398
15399
15400
15401
15402
15403
15404
15405
15406
15407
15408


15409
15410
15411
15412
15413
15414
15415
15416
15417
15418
15419
15420
15421
15422
15423
15424
15425
15426
15427
15428
15429
15430
15431
15432
15433
15434
15435
15436
15437
15438
15439
15440
15441
15442
15443
15444
15445
15446
15447
15448
15449
15450
15451
15452
15453
15454
15455
15456
15457
15458
15459
15460
15461
15462
15463
15464
15465
15466
15467
15468
15469
15470
15471
15472
15473
15474
15475
15476
15477
15478
15479
15480
15481
15482
15483
15484
#define OP_Not            19 /* same as TK_NOT, synopsis: r[P2]= !r[P1]    */
#define OP_IfNot          20 /* jump                                       */
#define OP_IfNullRow      21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
#define OP_SeekLT         22 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekLE         23 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekGE         24 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekGT         25 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IfNotOpen      26 /* jump, synopsis: if( !csr[P1] ) goto P2     */
#define OP_IfNoHope       27 /* jump, synopsis: key=r[P3@P4]               */
#define OP_NoConflict     28 /* jump, synopsis: key=r[P3@P4]               */
#define OP_NotFound       29 /* jump, synopsis: key=r[P3@P4]               */
#define OP_Found          30 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekRowid      31 /* jump, synopsis: intkey=r[P3]               */
#define OP_NotExists      32 /* jump, synopsis: intkey=r[P3]               */
#define OP_Last           33 /* jump                                       */
#define OP_IfSmaller      34 /* jump                                       */
#define OP_SorterSort     35 /* jump                                       */
#define OP_Sort           36 /* jump                                       */
#define OP_Rewind         37 /* jump                                       */
#define OP_IdxLE          38 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxGT          39 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxLT          40 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxGE          41 /* jump, synopsis: key=r[P3@P4]               */
#define OP_RowSetRead     42 /* jump, synopsis: r[P3]=rowset(P1)           */

#define OP_Or             43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And            44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
#define OP_RowSetTest     45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
#define OP_Program        46 /* jump                                       */
#define OP_FkIfZero       47 /* jump, synopsis: if fkctr[P1]==0 goto P2    */
#define OP_IfPos          48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
#define OP_IfNotZero      49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */

#define OP_IsNull         50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull        51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne             52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
#define OP_Eq             53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
#define OP_Gt             54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
#define OP_Le             55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
#define OP_Lt             56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge             57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseNotEq      58 /* jump, same as TK_ESCAPE                    */
#define OP_DecrJumpZero   59 /* jump, synopsis: if (--r[P1])==0 goto P2    */
#define OP_IncrVacuum     60 /* jump                                       */
#define OP_VNext          61 /* jump                                       */
#define OP_Init           62 /* jump, synopsis: Start at P2                */
#define OP_PureFunc       63 /* synopsis: r[P3]=func(r[P2@NP])             */
#define OP_Function       64 /* synopsis: r[P3]=func(r[P2@NP])             */
#define OP_Return         65
#define OP_EndCoroutine   66
#define OP_HaltIfNull     67 /* synopsis: if r[P3]=null halt               */
#define OP_Halt           68
#define OP_Integer        69 /* synopsis: r[P2]=P1                         */
#define OP_Int64          70 /* synopsis: r[P2]=P4                         */
#define OP_String         71 /* synopsis: r[P2]='P4' (len=P1)              */
#define OP_Null           72 /* synopsis: r[P2..P3]=NULL                   */
#define OP_SoftNull       73 /* synopsis: r[P1]=NULL                       */
#define OP_Blob           74 /* synopsis: r[P2]=P4 (len=P1)                */
#define OP_Variable       75 /* synopsis: r[P2]=parameter(P1,P4)           */
#define OP_Move           76 /* synopsis: r[P2@P3]=r[P1@P3]                */
#define OP_Copy           77 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
#define OP_SCopy          78 /* synopsis: r[P2]=r[P1]                      */
#define OP_IntCopy        79 /* synopsis: r[P2]=r[P1]                      */
#define OP_ResultRow      80 /* synopsis: output=r[P1@P2]                  */
#define OP_CollSeq        81
#define OP_AddImm         82 /* synopsis: r[P1]=r[P1]+P2                   */
#define OP_RealAffinity   83
#define OP_Cast           84 /* synopsis: affinity(r[P1])                  */
#define OP_Permutation    85
#define OP_Compare        86 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
#define OP_IsTrue         87 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
#define OP_Offset         88 /* synopsis: r[P3] = sqlite_offset(P1)        */
#define OP_Column         89 /* synopsis: r[P3]=PX                         */
#define OP_Affinity       90 /* synopsis: affinity(r[P1@P2])               */
#define OP_MakeRecord     91 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
#define OP_Count          92 /* synopsis: r[P2]=count()                    */
#define OP_ReadCookie     93
#define OP_SetCookie      94
#define OP_ReopenIdx      95 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenRead       96 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenWrite      97 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenDup        98
#define OP_OpenAutoindex  99 /* synopsis: nColumn=P2                       */
#define OP_OpenEphemeral 100 /* synopsis: nColumn=P2                       */

#define OP_BitAnd        101 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr         102 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft     103 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
#define OP_ShiftRight    104 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
#define OP_Add           105 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
#define OP_Subtract      106 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
#define OP_Multiply      107 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
#define OP_Divide        108 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
#define OP_Remainder     109 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
#define OP_Concat        110 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_SorterOpen    111
#define OP_BitNot        112 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
#define OP_SequenceTest  113 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
#define OP_OpenPseudo    114 /* synopsis: P3 columns in r[P2]              */

#define OP_String8       115 /* same as TK_STRING, synopsis: r[P2]='P4'    */
#define OP_Close         116
#define OP_ColumnsUsed   117
#define OP_SeekHit       118 /* synopsis: seekHit=P2                       */
#define OP_Sequence      119 /* synopsis: r[P2]=cursor[P1].ctr++           */
#define OP_NewRowid      120 /* synopsis: r[P2]=rowid                      */
#define OP_Insert        121 /* synopsis: intkey=r[P3] data=r[P2]          */
#define OP_Delete        122
#define OP_ResetCount    123
#define OP_SorterCompare 124 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
#define OP_SorterData    125 /* synopsis: r[P2]=data                       */
#define OP_RowData       126 /* synopsis: r[P2]=data                       */
#define OP_Rowid         127 /* synopsis: r[P2]=rowid                      */
#define OP_NullRow       128
#define OP_SeekEnd       129

#define OP_IdxInsert     130 /* synopsis: key=r[P2]                        */
#define OP_SorterInsert  131 /* synopsis: key=r[P2]                        */
#define OP_IdxDelete     132 /* synopsis: key=r[P2@P3]                     */
#define OP_DeferredSeek  133 /* synopsis: Move P3 to P1.rowid if needed    */
#define OP_IdxRowid      134 /* synopsis: r[P2]=rowid                      */
#define OP_FinishSeek    135
#define OP_Destroy       136
#define OP_Clear         137
#define OP_ResetSorter   138
#define OP_CreateBtree   139 /* synopsis: r[P2]=root iDb=P1 flags=P3       */
#define OP_SqlExec       140
#define OP_ParseSchema   141
#define OP_LoadAnalysis  142
#define OP_DropTable     143
#define OP_DropIndex     144
#define OP_DropTrigger   145
#define OP_IntegrityCk   146
#define OP_RowSetAdd     147 /* synopsis: rowset(P1)=r[P2]                 */
#define OP_Param         148
#define OP_FkCounter     149 /* synopsis: fkctr[P1]+=P2                    */


#define OP_Real          150 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
#define OP_MemMax        151 /* synopsis: r[P1]=max(r[P1],r[P2])           */
#define OP_OffsetLimit   152 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
#define OP_AggInverse    153 /* synopsis: accum=r[P3] inverse(r[P2@P5])    */
#define OP_AggStep       154 /* synopsis: accum=r[P3] step(r[P2@P5])       */
#define OP_AggStep1      155 /* synopsis: accum=r[P3] step(r[P2@P5])       */
#define OP_AggValue      156 /* synopsis: r[P3]=value N=P2                 */
#define OP_AggFinal      157 /* synopsis: accum=r[P1] N=P2                 */
#define OP_Expire        158
#define OP_CursorLock    159
#define OP_CursorUnlock  160
#define OP_TableLock     161 /* synopsis: iDb=P1 root=P2 write=P3          */
#define OP_VBegin        162
#define OP_VCreate       163
#define OP_VDestroy      164
#define OP_VOpen         165
#define OP_VColumn       166 /* synopsis: r[P3]=vcolumn(P2)                */
#define OP_VRename       167
#define OP_Pagecount     168
#define OP_MaxPgcnt      169
#define OP_Trace         170
#define OP_CursorHint    171
#define OP_ReleaseReg    172 /* synopsis: release r[P1@P2] mask P3         */
#define OP_Noop          173
#define OP_Explain       174
#define OP_Abortable     175

/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
*/
#define OPFLG_JUMP        0x01  /* jump:  P2 holds jmp target */
#define OPFLG_IN1         0x02  /* in1:   P1 is an input */
#define OPFLG_IN2         0x04  /* in2:   P2 is an input */
#define OPFLG_IN3         0x08  /* in3:   P3 is an input */
#define OPFLG_OUT2        0x10  /* out2:  P2 is an output */
#define OPFLG_OUT3        0x20  /* out3:  P3 is an output */
#define OPFLG_INITIALIZER {\
/*   0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\
/*   8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\
/*  16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\
/*  24 */ 0x09, 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09,\
/*  32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
/*  40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\
/*  48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
/*  56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x00,\
/*  64 */ 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10,\
/*  72 */ 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\
/*  80 */ 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x12,\
/*  88 */ 0x20, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
/*  96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
/* 112 */ 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\
/* 120 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
/* 128 */ 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00,\
/* 136 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
/* 144 */ 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x10, 0x04,\
/* 152 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 168 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
}

/* The sqlite3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode.  The smaller the maximum
** JUMP opcode the better, so the mkopcodeh.tcl script that
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
#define SQLITE_MX_JUMP_OPCODE  62  /* Maximum JUMP opcode */

/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/

/*
** Additional non-public SQLITE_PREPARE_* flags
*/
15258
15259
15260
15261
15262
15263
15264

15265
15266





15267
15268
15269
15270
15271
15272
15273
SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);

SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);





SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);







>


>
>
>
>
>







15537
15538
15539
15540
15541
15542
15543
15544
15545
15546
15547
15548
15549
15550
15551
15552
15553
15554
15555
15556
15557
15558
SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE   void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int);
#else
# define sqlite3VdbeReleaseRegisters(P,A,N,M,F)
#endif
SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
15548
15549
15550
15551
15552
15553
15554
15555
15556
15557
15558
15559
15560
15561
15562
15563
15564
);
SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);

/* Functions used to configure a Pager object. */
SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
#ifdef SQLITE_HAS_CODEC
SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*);
#endif
SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);







<
<
<







15833
15834
15835
15836
15837
15838
15839



15840
15841
15842
15843
15844
15845
15846
);
SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);

/* Functions used to configure a Pager object. */
SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);



SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
15623
15624
15625
15626
15627
15628
15629
15630
15631
15632
15633
15634
15635
15636
15637
15638
15639
15640
15641
15642
15643
15644
15645
15646
15647
15648
15649
15650
15651
15652
15653
15654
15655
15656
15657
15658
15659
15660
15661
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE   int sqlite3PagerRefcount(Pager*);
#endif
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
SQLITE_PRIVATE void sqlite3PagerResetLockTimeout(Pager *pPager);
#else
# define sqlite3PagerResetLockTimeout(X)
#endif

/* Functions used to truncate the database file. */
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);

SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);

#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
#endif

/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST)
SQLITE_PRIVATE   Pgno sqlite3PagerPagenumber(DbPage*);
SQLITE_PRIVATE   int sqlite3PagerIswriteable(DbPage*);
#endif
#ifdef SQLITE_TEST
SQLITE_PRIVATE   int *sqlite3PagerStats(Pager*);







|




















<
<
<
<







15905
15906
15907
15908
15909
15910
15911
15912
15913
15914
15915
15916
15917
15918
15919
15920
15921
15922
15923
15924
15925
15926
15927
15928
15929
15930
15931
15932




15933
15934
15935
15936
15937
15938
15939
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE   int sqlite3PagerRefcount(Pager*);
#endif
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int);
SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
SQLITE_PRIVATE void sqlite3PagerResetLockTimeout(Pager *pPager);
#else
# define sqlite3PagerResetLockTimeout(X)
#endif

/* Functions used to truncate the database file. */
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);

SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);





/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST)
SQLITE_PRIVATE   Pgno sqlite3PagerPagenumber(DbPage*);
SQLITE_PRIVATE   int sqlite3PagerIswriteable(DbPage*);
#endif
#ifdef SQLITE_TEST
SQLITE_PRIVATE   int *sqlite3PagerStats(Pager*);
16315
16316
16317
16318
16319
16320
16321
16322
16323
16324
16325
16326
16327
16328
16329
**
** DB_UnresetViews means that one or more views have column names that
** have been filled out.  If the schema changes, these column names might
** changes and so the view will need to be reset.
*/
#define DB_SchemaLoaded    0x0001  /* The schema has been loaded */
#define DB_UnresetViews    0x0002  /* Some views have defined column names */
#define DB_Empty           0x0004  /* The file is empty (length 0 bytes) */
#define DB_ResetWanted     0x0008  /* Reset the schema when nSchemaLock==0 */

/*
** The number of different kinds of things that can be limited
** using the sqlite3_limit() interface.
*/
#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1)







<







16593
16594
16595
16596
16597
16598
16599

16600
16601
16602
16603
16604
16605
16606
**
** DB_UnresetViews means that one or more views have column names that
** have been filled out.  If the schema changes, these column names might
** changes and so the view will need to be reset.
*/
#define DB_SchemaLoaded    0x0001  /* The schema has been loaded */
#define DB_UnresetViews    0x0002  /* Some views have defined column names */

#define DB_ResetWanted     0x0008  /* Reset the schema when nSchemaLock==0 */

/*
** The number of different kinds of things that can be limited
** using the sqlite3_limit() interface.
*/
#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1)
16349
16350
16351
16352
16353
16354
16355



















16356
16357
16358
16359
16360
16361
16362
16363
16364
16365






16366
16367
16368
16369
16370
16371
16372
16373
16374
16375







16376
16377
16378
16379
16380
16381
16382
** lookaside allocations are not used to construct the schema objects.
**
** New lookaside allocations are only allowed if bDisable==0.  When
** bDisable is greater than zero, sz is set to zero which effectively
** disables lookaside without adding a new test for the bDisable flag
** in a performance-critical path.  sz should be set by to szTrue whenever
** bDisable changes back to zero.



















*/
struct Lookaside {
  u32 bDisable;           /* Only operate the lookaside when zero */
  u16 sz;                 /* Size of each buffer in bytes */
  u16 szTrue;             /* True value of sz, even if disabled */
  u8 bMalloced;           /* True if pStart obtained from sqlite3_malloc() */
  u32 nSlot;              /* Number of lookaside slots allocated */
  u32 anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
  LookasideSlot *pInit;   /* List of buffers not previously used */
  LookasideSlot *pFree;   /* List of available buffers */






  void *pStart;           /* First byte of available memory space */
  void *pEnd;             /* First byte past end of available space */
};
struct LookasideSlot {
  LookasideSlot *pNext;    /* Next buffer in the list of free buffers */
};

#define DisableLookaside  db->lookaside.bDisable++;db->lookaside.sz=0
#define EnableLookaside   db->lookaside.bDisable--;\
   db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue








/*
** A hash table for built-in function definitions.  (Application-defined
** functions use a regular table table from hash.h.)
**
** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
** Collisions are on the FuncDef.u.pHash chain.  Use the SQLITE_FUNC_HASH()







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










>
>
>
>
>
>










>
>
>
>
>
>
>







16626
16627
16628
16629
16630
16631
16632
16633
16634
16635
16636
16637
16638
16639
16640
16641
16642
16643
16644
16645
16646
16647
16648
16649
16650
16651
16652
16653
16654
16655
16656
16657
16658
16659
16660
16661
16662
16663
16664
16665
16666
16667
16668
16669
16670
16671
16672
16673
16674
16675
16676
16677
16678
16679
16680
16681
16682
16683
16684
16685
16686
16687
16688
16689
16690
16691
** lookaside allocations are not used to construct the schema objects.
**
** New lookaside allocations are only allowed if bDisable==0.  When
** bDisable is greater than zero, sz is set to zero which effectively
** disables lookaside without adding a new test for the bDisable flag
** in a performance-critical path.  sz should be set by to szTrue whenever
** bDisable changes back to zero.
**
** Lookaside buffers are initially held on the pInit list.  As they are
** used and freed, they are added back to the pFree list.  New allocations
** come off of pFree first, then pInit as a fallback.  This dual-list
** allows use to compute a high-water mark - the maximum number of allocations
** outstanding at any point in the past - by subtracting the number of
** allocations on the pInit list from the total number of allocations.
**
** Enhancement on 2019-12-12:  Two-size-lookaside
** The default lookaside configuration is 100 slots of 1200 bytes each.
** The larger slot sizes are important for performance, but they waste
** a lot of space, as most lookaside allocations are less than 128 bytes.
** The two-size-lookaside enhancement breaks up the lookaside allocation
** into two pools:  One of 128-byte slots and the other of the default size
** (1200-byte) slots.   Allocations are filled from the small-pool first,
** failing over to the full-size pool if that does not work.  Thus more
** lookaside slots are available while also using less memory.
** This enhancement can be omitted by compiling with
** SQLITE_OMIT_TWOSIZE_LOOKASIDE.
*/
struct Lookaside {
  u32 bDisable;           /* Only operate the lookaside when zero */
  u16 sz;                 /* Size of each buffer in bytes */
  u16 szTrue;             /* True value of sz, even if disabled */
  u8 bMalloced;           /* True if pStart obtained from sqlite3_malloc() */
  u32 nSlot;              /* Number of lookaside slots allocated */
  u32 anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
  LookasideSlot *pInit;   /* List of buffers not previously used */
  LookasideSlot *pFree;   /* List of available buffers */
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
  LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
  LookasideSlot *pSmallFree; /* List of available small buffers */
  void *pMiddle;          /* First byte past end of full-size buffers and
                          ** the first byte of LOOKASIDE_SMALL buffers */
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
  void *pStart;           /* First byte of available memory space */
  void *pEnd;             /* First byte past end of available space */
};
struct LookasideSlot {
  LookasideSlot *pNext;    /* Next buffer in the list of free buffers */
};

#define DisableLookaside  db->lookaside.bDisable++;db->lookaside.sz=0
#define EnableLookaside   db->lookaside.bDisable--;\
   db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue

/* Size of the smaller allocations in two-size lookside */
#ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
#  define LOOKASIDE_SMALL           0
#else
#  define LOOKASIDE_SMALL         128
#endif

/*
** A hash table for built-in function definitions.  (Application-defined
** functions use a regular table table from hash.h.)
**
** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
** Collisions are on the FuncDef.u.pHash chain.  Use the SQLITE_FUNC_HASH()
16441
16442
16443
16444
16445
16446
16447
16448
16449
16450
16451
16452
16453
16454
16455

/*
** Each database connection is an instance of the following structure.
*/
struct sqlite3 {
  sqlite3_vfs *pVfs;            /* OS Interface */
  struct Vdbe *pVdbe;           /* List of active virtual machines */
  CollSeq *pDfltColl;           /* The default collating sequence (BINARY) */
  sqlite3_mutex *mutex;         /* Connection mutex */
  Db *aDb;                      /* All backends */
  int nDb;                      /* Number of backends currently in use */
  u32 mDbFlags;                 /* flags recording internal state */
  u64 flags;                    /* flags settable by pragmas. See below */
  i64 lastRowid;                /* ROWID of most recent insert (see above) */
  i64 szMmap;                   /* Default mmap_size setting */







|







16750
16751
16752
16753
16754
16755
16756
16757
16758
16759
16760
16761
16762
16763
16764

/*
** Each database connection is an instance of the following structure.
*/
struct sqlite3 {
  sqlite3_vfs *pVfs;            /* OS Interface */
  struct Vdbe *pVdbe;           /* List of active virtual machines */
  CollSeq *pDfltColl;           /* BINARY collseq for the database encoding */
  sqlite3_mutex *mutex;         /* Connection mutex */
  Db *aDb;                      /* All backends */
  int nDb;                      /* Number of backends currently in use */
  u32 mDbFlags;                 /* flags recording internal state */
  u64 flags;                    /* flags settable by pragmas. See below */
  i64 lastRowid;                /* ROWID of most recent insert (see above) */
  i64 szMmap;                   /* Default mmap_size setting */
16578
16579
16580
16581
16582
16583
16584







16585
16586
16587
16588
16589
16590
16591
16592
16593
16594
16595
16596
16597
16598
16599
16600
16601
16602
16603
16604
16605
16606
16607
16608
16609

/*
** A macro to discover the encoding of a database.
*/
#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
#define ENC(db)        ((db)->enc)








/*
** Possible values for the sqlite3.flags.
**
** Value constraints (enforced via assert()):
**      SQLITE_FullFSync     == PAGER_FULLFSYNC
**      SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
**      SQLITE_CacheSpill    == PAGER_CACHE_SPILL
*/
#define SQLITE_WriteSchema    0x00000001  /* OK to update SQLITE_MASTER */
#define SQLITE_LegacyFileFmt  0x00000002  /* Create new databases in format 1 */
#define SQLITE_FullColNames   0x00000004  /* Show full column names on SELECT */
#define SQLITE_FullFSync      0x00000008  /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync  0x00000010  /* Use full fsync for checkpoint */
#define SQLITE_CacheSpill     0x00000020  /* OK to spill pager cache */
#define SQLITE_ShortColNames  0x00000040  /* Show short columns names */
#define SQLITE_CountRows      0x00000080  /* Count rows changed by INSERT, */
                                          /*   DELETE, or UPDATE and return */
                                          /*   the count using a callback. */
#define SQLITE_NullCallback   0x00000100  /* Invoke the callback once if the */
                                          /*   result set is empty */
#define SQLITE_IgnoreChecks   0x00000200  /* Do not enforce check constraints */
#define SQLITE_ReadUncommit   0x00000400  /* READ UNCOMMITTED in shared-cache */
#define SQLITE_NoCkptOnClose  0x00000800  /* No checkpoint on close()/DETACH */
#define SQLITE_ReverseOrder   0x00001000  /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers    0x00002000  /* Enable recursive triggers */







>
>
>
>
>
>
>















|
|
<







16887
16888
16889
16890
16891
16892
16893
16894
16895
16896
16897
16898
16899
16900
16901
16902
16903
16904
16905
16906
16907
16908
16909
16910
16911
16912
16913
16914
16915
16916
16917

16918
16919
16920
16921
16922
16923
16924

/*
** A macro to discover the encoding of a database.
*/
#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
#define ENC(db)        ((db)->enc)

/*
** A u64 constant where the lower 32 bits are all zeros.  Only the
** upper 32 bits are included in the argument.  Necessary because some
** C-compilers still do not accept LL integer literals.
*/
#define HI(X)  ((u64)(X)<<32)

/*
** Possible values for the sqlite3.flags.
**
** Value constraints (enforced via assert()):
**      SQLITE_FullFSync     == PAGER_FULLFSYNC
**      SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
**      SQLITE_CacheSpill    == PAGER_CACHE_SPILL
*/
#define SQLITE_WriteSchema    0x00000001  /* OK to update SQLITE_MASTER */
#define SQLITE_LegacyFileFmt  0x00000002  /* Create new databases in format 1 */
#define SQLITE_FullColNames   0x00000004  /* Show full column names on SELECT */
#define SQLITE_FullFSync      0x00000008  /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync  0x00000010  /* Use full fsync for checkpoint */
#define SQLITE_CacheSpill     0x00000020  /* OK to spill pager cache */
#define SQLITE_ShortColNames  0x00000040  /* Show short columns names */
#define SQLITE_TrustedSchema  0x00000080  /* Allow unsafe functions and
                                          ** vtabs in the schema definition */

#define SQLITE_NullCallback   0x00000100  /* Invoke the callback once if the */
                                          /*   result set is empty */
#define SQLITE_IgnoreChecks   0x00000200  /* Do not enforce check constraints */
#define SQLITE_ReadUncommit   0x00000400  /* READ UNCOMMITTED in shared-cache */
#define SQLITE_NoCkptOnClose  0x00000800  /* No checkpoint on close()/DETACH */
#define SQLITE_ReverseOrder   0x00001000  /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers    0x00002000  /* Enable recursive triggers */
16621
16622
16623
16624
16625
16626
16627



16628
16629
16630
16631
16632
16633
16634
16635
16636
16637
16638
16639
16640
16641
16642
16643
16644
16645
16646
16647


16648
16649
16650
16651
16652
16653
16654
#define SQLITE_ResetDatabase  0x02000000  /* Reset the database */
#define SQLITE_LegacyAlter    0x04000000  /* Legacy ALTER TABLE behaviour */
#define SQLITE_NoSchemaError  0x08000000  /* Do not report schema parse errors*/
#define SQLITE_Defensive      0x10000000  /* Input SQL is likely hostile */
#define SQLITE_DqsDDL         0x20000000  /* dbl-quoted strings allowed in DDL*/
#define SQLITE_DqsDML         0x40000000  /* dbl-quoted strings allowed in DML*/
#define SQLITE_EnableView     0x80000000  /* Enable the use of views */




/* Flags used only if debugging */
#define HI(X)  ((u64)(X)<<32)
#ifdef SQLITE_DEBUG
#define SQLITE_SqlTrace       HI(0x0100000) /* Debug print SQL as it executes */
#define SQLITE_VdbeListing    HI(0x0200000) /* Debug listings of VDBE progs */
#define SQLITE_VdbeTrace      HI(0x0400000) /* True to trace VDBE execution */
#define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */
#define SQLITE_VdbeEQP        HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */
#define SQLITE_ParserTrace    HI(0x2000000) /* PRAGMA parser_trace=ON */
#endif

/*
** Allowed values for sqlite3.mDbFlags
*/
#define DBFLAG_SchemaChange   0x0001  /* Uncommitted Hash table changes */
#define DBFLAG_PreferBuiltin  0x0002  /* Preference to built-in funcs */
#define DBFLAG_Vacuum         0x0004  /* Currently in a VACUUM */
#define DBFLAG_VacuumInto     0x0008  /* Currently running VACUUM INTO */
#define DBFLAG_SchemaKnownOk  0x0010  /* Schema is known to be valid */



/*
** Bits of the sqlite3.dbOptFlags field that are used by the
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
** selectively disable various optimizations.
*/
#define SQLITE_QueryFlattener 0x0001   /* Query flattening */







>
>
>


<

















>
>







16936
16937
16938
16939
16940
16941
16942
16943
16944
16945
16946
16947

16948
16949
16950
16951
16952
16953
16954
16955
16956
16957
16958
16959
16960
16961
16962
16963
16964
16965
16966
16967
16968
16969
16970
16971
16972
16973
#define SQLITE_ResetDatabase  0x02000000  /* Reset the database */
#define SQLITE_LegacyAlter    0x04000000  /* Legacy ALTER TABLE behaviour */
#define SQLITE_NoSchemaError  0x08000000  /* Do not report schema parse errors*/
#define SQLITE_Defensive      0x10000000  /* Input SQL is likely hostile */
#define SQLITE_DqsDDL         0x20000000  /* dbl-quoted strings allowed in DDL*/
#define SQLITE_DqsDML         0x40000000  /* dbl-quoted strings allowed in DML*/
#define SQLITE_EnableView     0x80000000  /* Enable the use of views */
#define SQLITE_CountRows      HI(0x00001) /* Count rows changed by INSERT, */
                                          /*   DELETE, or UPDATE and return */
                                          /*   the count using a callback. */

/* Flags used only if debugging */

#ifdef SQLITE_DEBUG
#define SQLITE_SqlTrace       HI(0x0100000) /* Debug print SQL as it executes */
#define SQLITE_VdbeListing    HI(0x0200000) /* Debug listings of VDBE progs */
#define SQLITE_VdbeTrace      HI(0x0400000) /* True to trace VDBE execution */
#define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */
#define SQLITE_VdbeEQP        HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */
#define SQLITE_ParserTrace    HI(0x2000000) /* PRAGMA parser_trace=ON */
#endif

/*
** Allowed values for sqlite3.mDbFlags
*/
#define DBFLAG_SchemaChange   0x0001  /* Uncommitted Hash table changes */
#define DBFLAG_PreferBuiltin  0x0002  /* Preference to built-in funcs */
#define DBFLAG_Vacuum         0x0004  /* Currently in a VACUUM */
#define DBFLAG_VacuumInto     0x0008  /* Currently running VACUUM INTO */
#define DBFLAG_SchemaKnownOk  0x0010  /* Schema is known to be valid */
#define DBFLAG_InternalFunc   0x0020  /* Allow use of internal functions */
#define DBFLAG_EncodingFixed  0x0040  /* No longer possible to change enc. */

/*
** Bits of the sqlite3.dbOptFlags field that are used by the
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
** selectively disable various optimizations.
*/
#define SQLITE_QueryFlattener 0x0001   /* Query flattening */
16748
16749
16750
16751
16752
16753
16754

16755
16756
16757
16758
16759
16760
16761
16762
16763
16764
16765
16766
16767
16768
16769
16770
16771
16772
16773
16774
16775
16776










16777
16778
16779
16780
16781
16782
16783
16784
16785
16786
16787
16788
16789
16790
16791
















16792
16793
16794
16795
16796
16797
16798
**
** Value constraints (enforced via assert()):
**     SQLITE_FUNC_MINMAX    ==  NC_MinMaxAgg      == SF_MinMaxAgg
**     SQLITE_FUNC_LENGTH    ==  OPFLAG_LENGTHARG
**     SQLITE_FUNC_TYPEOF    ==  OPFLAG_TYPEOFARG
**     SQLITE_FUNC_CONSTANT  ==  SQLITE_DETERMINISTIC from the API
**     SQLITE_FUNC_DIRECT    ==  SQLITE_DIRECTONLY from the API

**     SQLITE_FUNC_ENCMASK   depends on SQLITE_UTF* macros in the API
*/
#define SQLITE_FUNC_ENCMASK  0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
#define SQLITE_FUNC_LIKE     0x0004 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE     0x0008 /* Case-sensitive LIKE-type function */
#define SQLITE_FUNC_EPHEM    0x0010 /* Ephemeral.  Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
#define SQLITE_FUNC_LENGTH   0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF   0x0080 /* Built-in typeof() function */
#define SQLITE_FUNC_COUNT    0x0100 /* Built-in count(*) aggregate */
#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
#define SQLITE_FUNC_MINMAX   0x1000 /* True for min() and max() aggregates */
#define SQLITE_FUNC_SLOCHNG  0x2000 /* "Slow Change". Value constant during a
                                    ** single query - might change over time */
#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
#define SQLITE_FUNC_OFFSET   0x8000 /* Built-in sqlite_offset() function */
#define SQLITE_FUNC_WINDOW   0x00010000 /* Built-in window-only function */
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
#define SQLITE_FUNC_DIRECT   0x00080000 /* Not for use in TRIGGERs or VIEWs */
#define SQLITE_FUNC_SUBTYPE  0x00100000 /* Result likely to have sub-type */











/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
** used to create the initializers for the FuncDef structures.
**
**   FUNCTION(zName, nArg, iArg, bNC, xFunc)
**     Used to create a scalar function definition of a function zName
**     implemented by C function xFunc that accepts nArg arguments. The
**     value passed as iArg is cast to a (void*) and made available
**     as the user-data (sqlite3_user_data()) for the function. If
**     argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
**
**   VFUNCTION(zName, nArg, iArg, bNC, xFunc)
**     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
**
















**   DFUNCTION(zName, nArg, iArg, bNC, xFunc)
**     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
**     adds the SQLITE_FUNC_SLOCHNG flag.  Used for date & time functions
**     and functions like sqlite_version() that can change, but not during
**     a single query.  The iArg is ignored.  The user-data is always set
**     to a NULL pointer.  The bNC parameter is not used.
**







>
















|





>
>
>
>
>
>
>
>
>
>















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







17067
17068
17069
17070
17071
17072
17073
17074
17075
17076
17077
17078
17079
17080
17081
17082
17083
17084
17085
17086
17087
17088
17089
17090
17091
17092
17093
17094
17095
17096
17097
17098
17099
17100
17101
17102
17103
17104
17105
17106
17107
17108
17109
17110
17111
17112
17113
17114
17115
17116
17117
17118
17119
17120
17121
17122
17123
17124
17125
17126
17127
17128
17129
17130
17131
17132
17133
17134
17135
17136
17137
17138
17139
17140
17141
17142
17143
17144
**
** Value constraints (enforced via assert()):
**     SQLITE_FUNC_MINMAX    ==  NC_MinMaxAgg      == SF_MinMaxAgg
**     SQLITE_FUNC_LENGTH    ==  OPFLAG_LENGTHARG
**     SQLITE_FUNC_TYPEOF    ==  OPFLAG_TYPEOFARG
**     SQLITE_FUNC_CONSTANT  ==  SQLITE_DETERMINISTIC from the API
**     SQLITE_FUNC_DIRECT    ==  SQLITE_DIRECTONLY from the API
**     SQLITE_FUNC_UNSAFE    ==  SQLITE_INNOCUOUS
**     SQLITE_FUNC_ENCMASK   depends on SQLITE_UTF* macros in the API
*/
#define SQLITE_FUNC_ENCMASK  0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
#define SQLITE_FUNC_LIKE     0x0004 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE     0x0008 /* Case-sensitive LIKE-type function */
#define SQLITE_FUNC_EPHEM    0x0010 /* Ephemeral.  Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
#define SQLITE_FUNC_LENGTH   0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF   0x0080 /* Built-in typeof() function */
#define SQLITE_FUNC_COUNT    0x0100 /* Built-in count(*) aggregate */
#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
#define SQLITE_FUNC_MINMAX   0x1000 /* True for min() and max() aggregates */
#define SQLITE_FUNC_SLOCHNG  0x2000 /* "Slow Change". Value constant during a
                                    ** single query - might change over time */
#define SQLITE_FUNC_TEST     0x4000 /* Built-in testing functions */
#define SQLITE_FUNC_OFFSET   0x8000 /* Built-in sqlite_offset() function */
#define SQLITE_FUNC_WINDOW   0x00010000 /* Built-in window-only function */
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
#define SQLITE_FUNC_DIRECT   0x00080000 /* Not for use in TRIGGERs or VIEWs */
#define SQLITE_FUNC_SUBTYPE  0x00100000 /* Result likely to have sub-type */
#define SQLITE_FUNC_UNSAFE   0x00200000 /* Function has side effects */
#define SQLITE_FUNC_INLINE   0x00400000 /* Functions implemented in-line */

/* Identifier numbers for each in-line function */
#define INLINEFUNC_coalesce             0
#define INLINEFUNC_implies_nonnull_row  1
#define INLINEFUNC_expr_implies_expr    2
#define INLINEFUNC_expr_compare         3      
#define INLINEFUNC_affinity             4
#define INLINEFUNC_unlikely            99  /* Default case */

/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
** used to create the initializers for the FuncDef structures.
**
**   FUNCTION(zName, nArg, iArg, bNC, xFunc)
**     Used to create a scalar function definition of a function zName
**     implemented by C function xFunc that accepts nArg arguments. The
**     value passed as iArg is cast to a (void*) and made available
**     as the user-data (sqlite3_user_data()) for the function. If
**     argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
**
**   VFUNCTION(zName, nArg, iArg, bNC, xFunc)
**     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
**
**   SFUNCTION(zName, nArg, iArg, bNC, xFunc)
**     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
**     adds the SQLITE_DIRECTONLY flag.
**
**   INLINE_FUNC(zName, nArg, iFuncId, mFlags)
**     zName is the name of a function that is implemented by in-line
**     byte code rather than by the usual callbacks. The iFuncId
**     parameter determines the function id.  The mFlags parameter is
**     optional SQLITE_FUNC_ flags for this function.
**
**   TEST_FUNC(zName, nArg, iFuncId, mFlags)
**     zName is the name of a test-only function implemented by in-line
**     byte code rather than by the usual callbacks. The iFuncId
**     parameter determines the function id.  The mFlags parameter is
**     optional SQLITE_FUNC_ flags for this function.
**
**   DFUNCTION(zName, nArg, iArg, bNC, xFunc)
**     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
**     adds the SQLITE_FUNC_SLOCHNG flag.  Used for date & time functions
**     and functions like sqlite_version() that can change, but not during
**     a single query.  The iArg is ignored.  The user-data is always set
**     to a NULL pointer.  The bNC parameter is not used.
**
16824
16825
16826
16827
16828
16829
16830










16831
16832
16833
16834
16835
16836
16837
16838
16839
16840
16841
16842
16843
16844
16845
16846
16847
16848
16849
16850
16851
16852
16853
16854
16855
16856
16857
16858
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }










#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
   0, 0, xFunc, 0, 0, 0, #zName, {0} }
#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
   (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} }
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
  {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
   pArg, 0, xFunc, 0, 0, 0, #zName, }
#define LIKEFUNC(zName, nArg, arg, flags) \
  {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
   (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} }
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue) \
  {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,0,#zName, {0}}
#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
  {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}}
#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \
  {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \
   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}}
#define INTERNAL_FUNCTION(zName, nArg, xFunc) \
  {nArg, SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
   0, 0, xFunc, 0, 0, 0, #zName, {0} }








>
>
>
>
>
>
>
>
>
>















<
<
<
<
<
<







17170
17171
17172
17173
17174
17175
17176
17177
17178
17179
17180
17181
17182
17183
17184
17185
17186
17187
17188
17189
17190
17191
17192
17193
17194
17195
17196
17197
17198
17199
17200
17201






17202
17203
17204
17205
17206
17207
17208
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
  {nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
   SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
#define TEST_FUNC(zName, nArg, iArg, mFlags) \
  {nArg, SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \
         SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
   SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
   0, 0, xFunc, 0, 0, 0, #zName, {0} }
#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
   (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} }
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
  {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
   pArg, 0, xFunc, 0, 0, 0, #zName, }
#define LIKEFUNC(zName, nArg, arg, flags) \
  {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
   (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} }






#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \
  {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \
   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}}
#define INTERNAL_FUNCTION(zName, nArg, xFunc) \
  {nArg, SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
   0, 0, xFunc, 0, 0, 0, #zName, {0} }

16913
16914
16915
16916
16917
16918
16919

16920
16921
16922
16923
16924
16925
16926
struct Column {
  char *zName;     /* Name of this column, \000, then the type */
  Expr *pDflt;     /* Default value or GENERATED ALWAYS AS value */
  char *zColl;     /* Collating sequence.  If NULL, use the default */
  u8 notNull;      /* An OE_ code for handling a NOT NULL constraint */
  char affinity;   /* One of the SQLITE_AFF_... values */
  u8 szEst;        /* Estimated size of value in this column. sizeof(INT)==1 */

  u16 colFlags;    /* Boolean properties.  See COLFLAG_ defines below */
};

/* Allowed values for Column.colFlags:
*/
#define COLFLAG_PRIMKEY   0x0001   /* Column is part of the primary key */
#define COLFLAG_HIDDEN    0x0002   /* A hidden column in a virtual table */







>







17263
17264
17265
17266
17267
17268
17269
17270
17271
17272
17273
17274
17275
17276
17277
struct Column {
  char *zName;     /* Name of this column, \000, then the type */
  Expr *pDflt;     /* Default value or GENERATED ALWAYS AS value */
  char *zColl;     /* Collating sequence.  If NULL, use the default */
  u8 notNull;      /* An OE_ code for handling a NOT NULL constraint */
  char affinity;   /* One of the SQLITE_AFF_... values */
  u8 szEst;        /* Estimated size of value in this column. sizeof(INT)==1 */
  u8 hName;        /* Column name hash for faster lookup */
  u16 colFlags;    /* Boolean properties.  See COLFLAG_ defines below */
};

/* Allowed values for Column.colFlags:
*/
#define COLFLAG_PRIMKEY   0x0001   /* Column is part of the primary key */
#define COLFLAG_HIDDEN    0x0002   /* A hidden column in a virtual table */
17046
17047
17048
17049
17050
17051
17052

17053
17054
17055






17056
17057
17058
17059
17060
17061
17062
*/
struct VTable {
  sqlite3 *db;              /* Database connection associated with this table */
  Module *pMod;             /* Pointer to module implementation */
  sqlite3_vtab *pVtab;      /* Pointer to vtab instance */
  int nRef;                 /* Number of pointers to this structure */
  u8 bConstraint;           /* True if constraints are supported */

  int iSavepoint;           /* Depth of the SAVEPOINT stack */
  VTable *pNext;            /* Next in linked list (see above) */
};







/*
** The schema for each SQL table and view is represented in memory
** by an instance of the following structure.
*/
struct Table {
  char *zName;         /* Name of the table or view */







>



>
>
>
>
>
>







17397
17398
17399
17400
17401
17402
17403
17404
17405
17406
17407
17408
17409
17410
17411
17412
17413
17414
17415
17416
17417
17418
17419
17420
*/
struct VTable {
  sqlite3 *db;              /* Database connection associated with this table */
  Module *pMod;             /* Pointer to module implementation */
  sqlite3_vtab *pVtab;      /* Pointer to vtab instance */
  int nRef;                 /* Number of pointers to this structure */
  u8 bConstraint;           /* True if constraints are supported */
  u8 eVtabRisk;             /* Riskiness of allowing hacker access */
  int iSavepoint;           /* Depth of the SAVEPOINT stack */
  VTable *pNext;            /* Next in linked list (see above) */
};

/* Allowed values for VTable.eVtabRisk
*/
#define SQLITE_VTABRISK_Low          0
#define SQLITE_VTABRISK_Normal       1
#define SQLITE_VTABRISK_High         2

/*
** The schema for each SQL table and view is represented in memory
** by an instance of the following structure.
*/
struct Table {
  char *zName;         /* Name of the table or view */
17125
17126
17127
17128
17129
17130
17131


17132
17133

17134
17135
17136
17137
17138
17139
17140
/*
** Test to see whether or not a table is a virtual table.  This is
** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#  define IsVirtual(X)      ((X)->nModuleArg)


#else
#  define IsVirtual(X)      0

#endif

/*
** Macros to determine if a column is hidden.  IsOrdinaryHiddenColumn()
** only works for non-virtual tables (ordinary tables and views) and is
** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined.  The
** IsHiddenColumn() macro is general purpose.







>
>


>







17483
17484
17485
17486
17487
17488
17489
17490
17491
17492
17493
17494
17495
17496
17497
17498
17499
17500
17501
/*
** Test to see whether or not a table is a virtual table.  This is
** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#  define IsVirtual(X)      ((X)->nModuleArg)
#  define ExprIsVtab(X)  \
              ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->nModuleArg)
#else
#  define IsVirtual(X)      0
#  define ExprIsVtab(X)     0
#endif

/*
** Macros to determine if a column is hidden.  IsOrdinaryHiddenColumn()
** only works for non-virtual tables (ordinary tables and views) and is
** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined.  The
** IsHiddenColumn() macro is general purpose.
17484
17485
17486
17487
17488
17489
17490
17491
17492
17493
17494
17495
17496
17497
17498
17499
17500
17501
/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits.  But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit.  16-bit is preferred because
** it uses less memory in the Expr object, which is a big memory user
** in systems with lots of prepared statements.  And few applications
** need more than about 10 or 20 variables.  But some extreme users want
** to have prepared statements with over 32767 variables, and for them
** the option is available (at compile-time).
*/
#if SQLITE_MAX_VARIABLE_NUMBER<=32767
typedef i16 ynVar;
#else
typedef int ynVar;
#endif

/*
** Each node of an expression in the parse tree is an instance







|


|







17845
17846
17847
17848
17849
17850
17851
17852
17853
17854
17855
17856
17857
17858
17859
17860
17861
17862
/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits.  But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit.  16-bit is preferred because
** it uses less memory in the Expr object, which is a big memory user
** in systems with lots of prepared statements.  And few applications
** need more than about 10 or 20 variables.  But some extreme users want
** to have prepared statements with over 32766 variables, and for them
** the option is available (at compile-time).
*/
#if SQLITE_MAX_VARIABLE_NUMBER<32767
typedef i16 ynVar;
#else
typedef int ynVar;
#endif

/*
** Each node of an expression in the parse tree is an instance
17563
17564
17565
17566
17567
17568
17569



17570
17571
17572
17573
17574
17575
17576
struct Expr {
  u8 op;                 /* Operation performed by this node */
  char affExpr;          /* affinity, or RAISE type */
  u8 op2;                /* TK_REGISTER/TK_TRUTH: original value of Expr.op
                         ** TK_COLUMN: the value of p5 for OP_Column
                         ** TK_AGG_FUNCTION: nesting depth
                         ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */



  u32 flags;             /* Various flags.  EP_* See below */
  union {
    char *zToken;          /* Token value. Zero terminated and dequoted */
    int iValue;            /* Non-negative integer value if EP_IntValue */
  } u;

  /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no







>
>
>







17924
17925
17926
17927
17928
17929
17930
17931
17932
17933
17934
17935
17936
17937
17938
17939
17940
struct Expr {
  u8 op;                 /* Operation performed by this node */
  char affExpr;          /* affinity, or RAISE type */
  u8 op2;                /* TK_REGISTER/TK_TRUTH: original value of Expr.op
                         ** TK_COLUMN: the value of p5 for OP_Column
                         ** TK_AGG_FUNCTION: nesting depth
                         ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */
#ifdef SQLITE_DEBUG
  u8 vvaFlags;           /* Verification flags. */
#endif
  u32 flags;             /* Various flags.  EP_* See below */
  union {
    char *zToken;          /* Token value. Zero terminated and dequoted */
    int iValue;            /* Non-negative integer value if EP_IntValue */
  } u;

  /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
17637
17638
17639
17640
17641
17642
17643
17644
17645
17646
17647
17648
17649
17650
17651
17652
17653
17654
17655
17656
17657

17658
17659
17660
17661
17662
17663
17664
17665
17666
17667
17668
17669
17670
17671
17672
17673
17674
17675






17676
17677
17678
17679
17680
17681


17682
17683


17684
17685
17686
17687
17688
17689
17690
#define EP_IntValue   0x000400 /* Integer value contained in u.iValue */
#define EP_xIsSelect  0x000800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Skip       0x001000 /* Operator does not contribute to affinity */
#define EP_Reduced    0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly  0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
#define EP_Win        0x008000 /* Contains window functions */
#define EP_MemToken   0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_NoReduce   0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_Unlikely   0x040000 /* unlikely() or likelihood() function */
#define EP_ConstFunc  0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
#define EP_CanBeNull  0x100000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery   0x200000 /* Tree contains a TK_SELECT operator */
#define EP_Alias      0x400000 /* Is an alias for a result set column */
#define EP_Leaf       0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
#define EP_WinFunc   0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
#define EP_Subrtn    0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
#define EP_Quoted    0x4000000 /* TK_ID was originally quoted */
#define EP_Static    0x8000000 /* Held in memory not obtained from malloc() */
#define EP_IsTrue   0x10000000 /* Always has boolean value of TRUE */
#define EP_IsFalse  0x20000000 /* Always has boolean value of FALSE */
#define EP_Indirect 0x40000000 /* Contained within a TRIGGER or a VIEW */


/*
** The EP_Propagate mask is a set of properties that automatically propagate
** upwards into parent nodes.
*/
#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)

/*
** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
#define ExprHasProperty(E,P)     (((E)->flags&(P))!=0)
#define ExprHasAllProperty(E,P)  (((E)->flags&(P))==(P))
#define ExprSetProperty(E,P)     (E)->flags|=(P)
#define ExprClearProperty(E,P)   (E)->flags&=~(P)
#define ExprAlwaysTrue(E)   (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E)  (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse)







/* The ExprSetVVAProperty() macro is used for Verification, Validation,
** and Accreditation only.  It works like ExprSetProperty() during VVA
** processes but is a no-op for delivery.
*/
#ifdef SQLITE_DEBUG
# define ExprSetVVAProperty(E,P)  (E)->flags|=(P)


#else
# define ExprSetVVAProperty(E,P)


#endif

/*
** Macros to determine the number of bytes required by a normal Expr
** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
** and an Expr struct with the EP_TokenOnly flag set.
*/







|












|
>


















>
>
>
>
>
>





|
>
>


>
>







18001
18002
18003
18004
18005
18006
18007
18008
18009
18010
18011
18012
18013
18014
18015
18016
18017
18018
18019
18020
18021
18022
18023
18024
18025
18026
18027
18028
18029
18030
18031
18032
18033
18034
18035
18036
18037
18038
18039
18040
18041
18042
18043
18044
18045
18046
18047
18048
18049
18050
18051
18052
18053
18054
18055
18056
18057
18058
18059
18060
18061
18062
18063
18064
18065
#define EP_IntValue   0x000400 /* Integer value contained in u.iValue */
#define EP_xIsSelect  0x000800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Skip       0x001000 /* Operator does not contribute to affinity */
#define EP_Reduced    0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly  0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
#define EP_Win        0x008000 /* Contains window functions */
#define EP_MemToken   0x010000 /* Need to sqlite3DbFree() Expr.zToken */
                  /*  0x020000 // available for reuse */
#define EP_Unlikely   0x040000 /* unlikely() or likelihood() function */
#define EP_ConstFunc  0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
#define EP_CanBeNull  0x100000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery   0x200000 /* Tree contains a TK_SELECT operator */
#define EP_Alias      0x400000 /* Is an alias for a result set column */
#define EP_Leaf       0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
#define EP_WinFunc   0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
#define EP_Subrtn    0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
#define EP_Quoted    0x4000000 /* TK_ID was originally quoted */
#define EP_Static    0x8000000 /* Held in memory not obtained from malloc() */
#define EP_IsTrue   0x10000000 /* Always has boolean value of TRUE */
#define EP_IsFalse  0x20000000 /* Always has boolean value of FALSE */
#define EP_FromDDL  0x40000000 /* Originates from sqlite_master */
               /*   0x80000000 // Available */

/*
** The EP_Propagate mask is a set of properties that automatically propagate
** upwards into parent nodes.
*/
#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)

/*
** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
#define ExprHasProperty(E,P)     (((E)->flags&(P))!=0)
#define ExprHasAllProperty(E,P)  (((E)->flags&(P))==(P))
#define ExprSetProperty(E,P)     (E)->flags|=(P)
#define ExprClearProperty(E,P)   (E)->flags&=~(P)
#define ExprAlwaysTrue(E)   (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E)  (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse)


/* Flags for use with Expr.vvaFlags
*/
#define EP_NoReduce   0x01  /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_Immutable  0x02  /* Do not change this Expr node */

/* The ExprSetVVAProperty() macro is used for Verification, Validation,
** and Accreditation only.  It works like ExprSetProperty() during VVA
** processes but is a no-op for delivery.
*/
#ifdef SQLITE_DEBUG
# define ExprSetVVAProperty(E,P)   (E)->vvaFlags|=(P)
# define ExprHasVVAProperty(E,P)   (((E)->vvaFlags&(P))!=0)
# define ExprClearVVAProperties(E) (E)->vvaFlags = 0
#else
# define ExprSetVVAProperty(E,P)
# define ExprHasVVAProperty(E,P)   0
# define ExprClearVVAProperties(E)
#endif

/*
** Macros to determine the number of bytes required by a normal Expr
** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
** and an Expr struct with the EP_TokenOnly flag set.
*/
17714
17715
17716
17717
17718
17719
17720
17721
17722
17723
17724
17725
17726
17727






17728
17729
17730
17731
17732
17733
17734
17735

17736
17737
17738
17739
17740
17741
17742
17743
17744
17745
17746
17747
17748
17749
17750







17751
17752
17753
17754
17755
17756
17757
** A list of expressions.  Each expression may optionally have a
** name.  An expr/name combination can be used in several ways, such
** as the list of "expr AS ID" fields following a "SELECT" or in the
** list of "ID = expr" items in an UPDATE.  A list of expressions can
** also be used as the argument to a function, in which case the a.zName
** field is not used.
**
** By default the Expr.zSpan field holds a human-readable description of
** the expression that is used in the generation of error messages and
** column labels.  In this case, Expr.zSpan is typically the text of a
** column expression as it exists in a SELECT statement.  However, if
** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
** of the result column in the form: DATABASE.TABLE.COLUMN.  This later
** form is used for name resolution with nested FROM clauses.






*/
struct ExprList {
  int nExpr;             /* Number of expressions on the list */
  struct ExprList_item { /* For each expression in the list */
    Expr *pExpr;            /* The parse tree for this expression */
    char *zName;            /* Token associated with this expression */
    char *zSpan;            /* Original text of the expression */
    u8 sortFlags;           /* Mask of KEYINFO_ORDER_* flags */

    unsigned done :1;       /* A flag to indicate when processing is finished */
    unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
    unsigned reusable :1;   /* Constant expression is reusable */
    unsigned bSorterRef :1; /* Defer evaluation until after sorting */
    unsigned bNulls: 1;     /* True if explicit "NULLS FIRST/LAST" */
    union {
      struct {
        u16 iOrderByCol;      /* For ORDER BY, column number in result set */
        u16 iAlias;           /* Index into Parse.aAlias[] for zName */
      } x;
      int iConstExprReg;      /* Register in which Expr value is cached */
    } u;
  } a[1];                  /* One slot for each expression in the list */
};








/*
** An instance of this structure can hold a simple list of identifiers,
** such as the list "a,b,c" in the following statements:
**
**      INSERT INTO t(a,b,c) VALUES ...;
**      CREATE INDEX idx ON t(a,b,c);
**      CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...;







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





|
<

>

<













>
>
>
>
>
>
>







18089
18090
18091
18092
18093
18094
18095
18096
18097
18098
18099
18100
18101
18102
18103
18104
18105
18106
18107
18108
18109
18110
18111
18112
18113
18114

18115
18116
18117

18118
18119
18120
18121
18122
18123
18124
18125
18126
18127
18128
18129
18130
18131
18132
18133
18134
18135
18136
18137
18138
18139
18140
18141
18142
18143
18144
** A list of expressions.  Each expression may optionally have a
** name.  An expr/name combination can be used in several ways, such
** as the list of "expr AS ID" fields following a "SELECT" or in the
** list of "ID = expr" items in an UPDATE.  A list of expressions can
** also be used as the argument to a function, in which case the a.zName
** field is not used.
**
** In order to try to keep memory usage down, the Expr.a.zEName field
** is used for multiple purposes:
**
**     eEName          Usage
**    ----------       -------------------------
**    ENAME_NAME       (1) the AS of result set column
**                     (2) COLUMN= of an UPDATE
**
**    ENAME_TAB        DB.TABLE.NAME used to resolve names
**                     of subqueries
**
**    ENAME_SPAN       Text of the original result set
**                     expression.
*/
struct ExprList {
  int nExpr;             /* Number of expressions on the list */
  struct ExprList_item { /* For each expression in the list */
    Expr *pExpr;            /* The parse tree for this expression */
    char *zEName;           /* Token associated with this expression */

    u8 sortFlags;           /* Mask of KEYINFO_ORDER_* flags */
    unsigned eEName :2;     /* Meaning of zEName */
    unsigned done :1;       /* A flag to indicate when processing is finished */

    unsigned reusable :1;   /* Constant expression is reusable */
    unsigned bSorterRef :1; /* Defer evaluation until after sorting */
    unsigned bNulls: 1;     /* True if explicit "NULLS FIRST/LAST" */
    union {
      struct {
        u16 iOrderByCol;      /* For ORDER BY, column number in result set */
        u16 iAlias;           /* Index into Parse.aAlias[] for zName */
      } x;
      int iConstExprReg;      /* Register in which Expr value is cached */
    } u;
  } a[1];                  /* One slot for each expression in the list */
};

/*
** Allowed values for Expr.a.eEName
*/
#define ENAME_NAME  0       /* The AS clause of a result set */
#define ENAME_SPAN  1       /* Complete text of the result set expression */
#define ENAME_TAB   2       /* "DB.TABLE.NAME" for the result set */

/*
** An instance of this structure can hold a simple list of identifiers,
** such as the list "a,b,c" in the following statements:
**
**      INSERT INTO t(a,b,c) VALUES ...;
**      CREATE INDEX idx ON t(a,b,c);
**      CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...;
17807
17808
17809
17810
17811
17812
17813

17814
17815
17816
17817
17818
17819
17820
      u8 jointype;      /* Type of join between this table and the previous */
      unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
      unsigned isIndexedBy :1;   /* True if there is an INDEXED BY clause */
      unsigned isTabFunc :1;     /* True if table-valued-function syntax */
      unsigned isCorrelated :1;  /* True if sub-query is correlated */
      unsigned viaCoroutine :1;  /* Implemented as a co-routine */
      unsigned isRecursive :1;   /* True for recursive reference in WITH */

    } fg;
    int iCursor;      /* The VDBE cursor number used to access this table */
    Expr *pOn;        /* The ON clause of a join */
    IdList *pUsing;   /* The USING clause of a join */
    Bitmask colUsed;  /* Bit N (1<<N) set if column N of pTab is used */
    union {
      char *zIndexedBy;    /* Identifier from "INDEXED BY <zIndex>" clause */







>







18194
18195
18196
18197
18198
18199
18200
18201
18202
18203
18204
18205
18206
18207
18208
      u8 jointype;      /* Type of join between this table and the previous */
      unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
      unsigned isIndexedBy :1;   /* True if there is an INDEXED BY clause */
      unsigned isTabFunc :1;     /* True if table-valued-function syntax */
      unsigned isCorrelated :1;  /* True if sub-query is correlated */
      unsigned viaCoroutine :1;  /* Implemented as a co-routine */
      unsigned isRecursive :1;   /* True for recursive reference in WITH */
      unsigned fromDDL :1;       /* Comes from sqlite_master */
    } fg;
    int iCursor;      /* The VDBE cursor number used to access this table */
    Expr *pOn;        /* The ON clause of a join */
    IdList *pUsing;   /* The USING clause of a join */
    Bitmask colUsed;  /* Bit N (1<<N) set if column N of pTab is used */
    union {
      char *zIndexedBy;    /* Identifier from "INDEXED BY <zIndex>" clause */
17927
17928
17929
17930
17931
17932
17933

17934
17935
17936
17937
17938
17939
17940
#define NC_UUpsert   0x00200  /* True if uNC.pUpsert is used */
#define NC_MinMaxAgg 0x01000  /* min/max aggregates seen.  See note above */
#define NC_Complex   0x02000  /* True if a function or subquery seen */
#define NC_AllowWin  0x04000  /* Window functions are allowed here */
#define NC_HasWin    0x08000  /* One or more window functions seen */
#define NC_IsDDL     0x10000  /* Resolving names in a CREATE statement */
#define NC_InAggFunc 0x20000  /* True if analyzing arguments to an agg func */


/*
** An instance of the following object describes a single ON CONFLICT
** clause in an upsert.
**
** The pUpsertTarget field is only set if the ON CONFLICT clause includes
** conflict-target clause.  (In "ON CONFLICT(a,b)" the "(a,b)" is the







>







18315
18316
18317
18318
18319
18320
18321
18322
18323
18324
18325
18326
18327
18328
18329
#define NC_UUpsert   0x00200  /* True if uNC.pUpsert is used */
#define NC_MinMaxAgg 0x01000  /* min/max aggregates seen.  See note above */
#define NC_Complex   0x02000  /* True if a function or subquery seen */
#define NC_AllowWin  0x04000  /* Window functions are allowed here */
#define NC_HasWin    0x08000  /* One or more window functions seen */
#define NC_IsDDL     0x10000  /* Resolving names in a CREATE statement */
#define NC_InAggFunc 0x20000  /* True if analyzing arguments to an agg func */
#define NC_FromDDL   0x40000  /* SQL text comes from sqlite_master */

/*
** An instance of the following object describes a single ON CONFLICT
** clause in an upsert.
**
** The pUpsertTarget field is only set if the ON CONFLICT clause includes
** conflict-target clause.  (In "ON CONFLICT(a,b)" the "(a,b)" is the
17976
17977
17978
17979
17980
17981
17982
17983
17984
17985
17986
17987
17988
17989

17990
17991
17992
17993
17994
17995
17996
** as the OP_OpenEphm instruction is coded because not
** enough information about the compound query is known at that point.
** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences
** for the result set.  The KeyInfo for addrOpenEphm[2] contains collating
** sequences for the ORDER BY clause.
*/
struct Select {
  ExprList *pEList;      /* The fields of the result */
  u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
  LogEst nSelectRow;     /* Estimated number of result rows */
  u32 selFlags;          /* Various SF_* values */
  int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
  u32 selId;             /* Unique identifier number for this SELECT */
  int addrOpenEphm[2];   /* OP_OpenEphem opcodes related to this select */

  SrcList *pSrc;         /* The FROM clause */
  Expr *pWhere;          /* The WHERE clause */
  ExprList *pGroupBy;    /* The GROUP BY clause */
  Expr *pHaving;         /* The HAVING clause */
  ExprList *pOrderBy;    /* The ORDER BY clause */
  Select *pPrior;        /* Prior select in a compound select statement */
  Select *pNext;         /* Next select to the left in a compound */







<






>







18365
18366
18367
18368
18369
18370
18371

18372
18373
18374
18375
18376
18377
18378
18379
18380
18381
18382
18383
18384
18385
** as the OP_OpenEphm instruction is coded because not
** enough information about the compound query is known at that point.
** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences
** for the result set.  The KeyInfo for addrOpenEphm[2] contains collating
** sequences for the ORDER BY clause.
*/
struct Select {

  u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
  LogEst nSelectRow;     /* Estimated number of result rows */
  u32 selFlags;          /* Various SF_* values */
  int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
  u32 selId;             /* Unique identifier number for this SELECT */
  int addrOpenEphm[2];   /* OP_OpenEphem opcodes related to this select */
  ExprList *pEList;      /* The fields of the result */
  SrcList *pSrc;         /* The FROM clause */
  Expr *pWhere;          /* The WHERE clause */
  ExprList *pGroupBy;    /* The GROUP BY clause */
  Expr *pHaving;         /* The HAVING clause */
  ExprList *pOrderBy;    /* The ORDER BY clause */
  Select *pPrior;        /* Prior select in a compound select statement */
  Select *pNext;         /* Next select to the left in a compound */
18028
18029
18030
18031
18032
18033
18034

18035
18036
18037
18038
18039
18040
18041
#define SF_FixedLimit    0x0004000 /* nSelectRow set by a constant LIMIT */
#define SF_MaybeConvert  0x0008000 /* Need convertCompoundSelectToSubquery() */
#define SF_Converted     0x0010000 /* By convertCompoundSelectToSubquery() */
#define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */
#define SF_ComplexResult 0x0040000 /* Result contains subquery or function */
#define SF_WhereBegin    0x0080000 /* Really a WhereBegin() call.  Debug Only */
#define SF_WinRewrite    0x0100000 /* Window function rewrite accomplished */


/*
** The results of a SELECT can be distributed in several ways, as defined
** by one of the following macros.  The "SRT" prefix means "SELECT Result
** Type".
**
**     SRT_Union       Store results as a key in a temporary index







>







18417
18418
18419
18420
18421
18422
18423
18424
18425
18426
18427
18428
18429
18430
18431
#define SF_FixedLimit    0x0004000 /* nSelectRow set by a constant LIMIT */
#define SF_MaybeConvert  0x0008000 /* Need convertCompoundSelectToSubquery() */
#define SF_Converted     0x0010000 /* By convertCompoundSelectToSubquery() */
#define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */
#define SF_ComplexResult 0x0040000 /* Result contains subquery or function */
#define SF_WhereBegin    0x0080000 /* Really a WhereBegin() call.  Debug Only */
#define SF_WinRewrite    0x0100000 /* Window function rewrite accomplished */
#define SF_View          0x0200000 /* SELECT statement is a view */

/*
** The results of a SELECT can be distributed in several ways, as defined
** by one of the following macros.  The "SRT" prefix means "SELECT Result
** Type".
**
**     SRT_Union       Store results as a key in a temporary index
18307
18308
18309
18310
18311
18312
18313
18314
18315
18316
18317
18318
18319
18320
18321
18322
#ifndef SQLITE_OMIT_ALTERTABLE
  RenameToken *pRename;     /* Tokens subject to renaming by ALTER TABLE */
#endif
};

#define PARSE_MODE_NORMAL        0
#define PARSE_MODE_DECLARE_VTAB  1
#define PARSE_MODE_RENAME_COLUMN 2
#define PARSE_MODE_RENAME_TABLE  3

/*
** Sizes and pointers of various parts of the Parse object.
*/
#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/
#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken)    /* Recursive part */
#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */







|
|







18697
18698
18699
18700
18701
18702
18703
18704
18705
18706
18707
18708
18709
18710
18711
18712
#ifndef SQLITE_OMIT_ALTERTABLE
  RenameToken *pRename;     /* Tokens subject to renaming by ALTER TABLE */
#endif
};

#define PARSE_MODE_NORMAL        0
#define PARSE_MODE_DECLARE_VTAB  1
#define PARSE_MODE_RENAME        2
#define PARSE_MODE_UNMAP         3

/*
** Sizes and pointers of various parts of the Parse object.
*/
#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/
#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken)    /* Recursive part */
#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
18330
18331
18332
18333
18334
18335
18336
18337
18338
18339
18340
18341
18342
18343
18344
#else
  #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB)
#endif

#if defined(SQLITE_OMIT_ALTERTABLE)
  #define IN_RENAME_OBJECT 0
#else
  #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME_COLUMN)
#endif

#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)
  #define IN_SPECIAL_PARSE 0
#else
  #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL)
#endif







|







18720
18721
18722
18723
18724
18725
18726
18727
18728
18729
18730
18731
18732
18733
18734
#else
  #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB)
#endif

#if defined(SQLITE_OMIT_ALTERTABLE)
  #define IN_RENAME_OBJECT 0
#else
  #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME)
#endif

#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)
  #define IN_SPECIAL_PARSE 0
#else
  #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL)
#endif
18481
18482
18483
18484
18485
18486
18487
18488
18489
18490
18491
18492
18493
18494
18495
** routines as they walk the parse tree to make database references
** explicit.
*/
typedef struct DbFixer DbFixer;
struct DbFixer {
  Parse *pParse;      /* The parsing context.  Error messages written here */
  Schema *pSchema;    /* Fix items to this schema */
  int bVarOnly;       /* Check for variable references only */
  const char *zDb;    /* Make sure all objects are contained in this database */
  const char *zType;  /* Type of the container - used for error messages */
  const Token *pName; /* Name of the container - used for error messages */
};

/*
** An objected used to accumulate the text of a string where we







|







18871
18872
18873
18874
18875
18876
18877
18878
18879
18880
18881
18882
18883
18884
18885
** routines as they walk the parse tree to make database references
** explicit.
*/
typedef struct DbFixer DbFixer;
struct DbFixer {
  Parse *pParse;      /* The parsing context.  Error messages written here */
  Schema *pSchema;    /* Fix items to this schema */
  u8 bTemp;           /* True for TEMP schema entries */
  const char *zDb;    /* Make sure all objects are contained in this database */
  const char *zType;  /* Type of the container - used for error messages */
  const Token *pName; /* Name of the container - used for error messages */
};

/*
** An objected used to accumulate the text of a string where we
18586
18587
18588
18589
18590
18591
18592
18593
18594
18595
18596
18597
18598
18599
18600
#ifdef SQLITE_ENABLE_DESERIALIZE
  sqlite3_int64 mxMemdbSize;        /* Default max memdb size */
#endif
#ifndef SQLITE_UNTESTABLE
  int (*xTestCallback)(int);        /* Invoked by sqlite3FaultSim() */
#endif
  int bLocaltimeFault;              /* True to fail localtime() calls */
  int bInternalFunctions;           /* Internal SQL functions are visible */
  int iOnceResetThreshold;          /* When to reset OP_Once counters */
  u32 szSorterRef;                  /* Min size in bytes to use sorter-refs */
  unsigned int iPrngSeed;           /* Alternative fixed seed for the PRNG */
};

/*
** This macro is used inside of assert() statements to indicate that







<







18976
18977
18978
18979
18980
18981
18982

18983
18984
18985
18986
18987
18988
18989
#ifdef SQLITE_ENABLE_DESERIALIZE
  sqlite3_int64 mxMemdbSize;        /* Default max memdb size */
#endif
#ifndef SQLITE_UNTESTABLE
  int (*xTestCallback)(int);        /* Invoked by sqlite3FaultSim() */
#endif
  int bLocaltimeFault;              /* True to fail localtime() calls */

  int iOnceResetThreshold;          /* When to reset OP_Once counters */
  u32 szSorterRef;                  /* Min size in bytes to use sorter-refs */
  unsigned int iPrngSeed;           /* Alternative fixed seed for the PRNG */
};

/*
** This macro is used inside of assert() statements to indicate that
18636
18637
18638
18639
18640
18641
18642

18643
18644
18645
18646
18647
18648
18649
    struct IdxExprTrans *pIdxTrans;           /* Convert idxed expr to column */
    ExprList *pGroupBy;                       /* GROUP BY clause */
    Select *pSelect;                          /* HAVING to WHERE clause ctx */
    struct WindowRewrite *pRewrite;           /* Window rewrite context */
    struct WhereConst *pConst;                /* WHERE clause constants */
    struct RenameCtx *pRename;                /* RENAME COLUMN context */
    struct Table *pTab;                       /* Table of generated column */

  } u;
};

/* Forward declarations */
SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*);
SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);







>







19025
19026
19027
19028
19029
19030
19031
19032
19033
19034
19035
19036
19037
19038
19039
    struct IdxExprTrans *pIdxTrans;           /* Convert idxed expr to column */
    ExprList *pGroupBy;                       /* GROUP BY clause */
    Select *pSelect;                          /* HAVING to WHERE clause ctx */
    struct WindowRewrite *pRewrite;           /* Window rewrite context */
    struct WhereConst *pConst;                /* WHERE clause constants */
    struct RenameCtx *pRename;                /* RENAME COLUMN context */
    struct Table *pTab;                       /* Table of generated column */
    struct SrcList_item *pSrcItem;            /* A single FROM clause item */
  } u;
};

/* Forward declarations */
SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*);
SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);
18749
18750
18751
18752
18753
18754
18755
18756
18757
18758
18759
18760
18761
18762
18763
SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*);
SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*);
SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*);
SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin);
SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*, int);
SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Window*);
SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*);
SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p);
SQLITE_PRIVATE void sqlite3WindowFunctions(void);







|







19139
19140
19141
19142
19143
19144
19145
19146
19147
19148
19149
19150
19151
19152
19153
SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*);
SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*);
SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*);
SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin);
SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*, int);
SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Select*);
SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*);
SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p);
SQLITE_PRIVATE void sqlite3WindowFunctions(void);
18792
18793
18794
18795
18796
18797
18798
18799
18800
18801
18802
18803
18804
18805





18806
18807
18808
18809
18810
18811
18812
SQLITE_PRIVATE int sqlite3CantopenError(int);
#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__)
#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE   int sqlite3NomemError(int);
SQLITE_PRIVATE   int sqlite3IoerrnomemError(int);
SQLITE_PRIVATE   int sqlite3CorruptPgnoError(int,Pgno);
# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)
# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
#else
# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM





# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
#endif

/*
** FTS3 and FTS4 both require virtual table support
*/
#if defined(SQLITE_OMIT_VIRTUALTABLE)







<


<



>
>
>
>
>







19182
19183
19184
19185
19186
19187
19188

19189
19190

19191
19192
19193
19194
19195
19196
19197
19198
19199
19200
19201
19202
19203
19204
19205
SQLITE_PRIVATE int sqlite3CantopenError(int);
#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__)
#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE   int sqlite3NomemError(int);
SQLITE_PRIVATE   int sqlite3IoerrnomemError(int);

# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)

#else
# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)
SQLITE_PRIVATE   int sqlite3CorruptPgnoError(int,Pgno);
# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
#else
# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
#endif

/*
** FTS3 and FTS4 both require virtual table support
*/
#if defined(SQLITE_OMIT_VIRTUALTABLE)
19015
19016
19017
19018
19019
19020
19021

19022
19023
19024
19025
19026
19027
19028
SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int);

SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);







>







19408
19409
19410
19411
19412
19413
19414
19415
19416
19417
19418
19419
19420
19421
19422
SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int);
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*);
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
19065
19066
19067
19068
19069
19070
19071
19072
19073
19074
19075
19076
19077
19078
19079
19080
19081
19082
19083
19084
19085
19086
19087
19088
SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE   int sqlite3UriCount(const char*);
#endif
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
                    sqlite3_vfs**,char**,char **);
#ifdef SQLITE_HAS_CODEC
SQLITE_PRIVATE   int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*);
#else
# define sqlite3CodecQueryParameters(A,B,C) 0
#endif
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);

#ifdef SQLITE_UNTESTABLE
# define sqlite3FaultSim(X) SQLITE_OK
#else
SQLITE_PRIVATE   int sqlite3FaultSim(int);
#endif







<
<
<


<
<
<
|
<







19459
19460
19461
19462
19463
19464
19465



19466
19467



19468

19469
19470
19471
19472
19473
19474
19475
SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);



SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
                    sqlite3_vfs**,char**,char **);



#define sqlite3CodecQueryParameters(A,B,C) 0

SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);

#ifdef SQLITE_UNTESTABLE
# define sqlite3FaultSim(X) SQLITE_OK
#else
SQLITE_PRIVATE   int sqlite3FaultSim(int);
#endif
19149
19150
19151
19152
19153
19154
19155

19156
19157
19158
19159
19160
19161
19162
SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
                          Expr*, int, int, u8);
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
                         Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);

SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
#endif
SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);







>







19536
19537
19538
19539
19540
19541
19542
19543
19544
19545
19546
19547
19548
19549
19550
SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
                          Expr*, int, int, u8);
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
                         Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
SQLITE_PRIVATE void sqlite3SelectReset(Parse*, Select*);
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
#endif
SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
19171
19172
19173
19174
19175
19176
19177

19178
19179
19180
19181
19182
19183
19184
19185
19186
19187
19188
19189
19190
19191
19192
19193
19194
19195
SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*);
#define ONEPASS_OFF      0        /* Use of ONEPASS not allowed */
#define ONEPASS_SINGLE   1        /* ONEPASS valid for a single row update */
#define ONEPASS_MULTI    2        /* ONEPASS is valid for multiple rows */

SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int);
#endif
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeAtInit(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
#define SQLITE_ECEL_DUP      0x01  /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR   0x02  /* Factor out constant terms */
#define SQLITE_ECEL_REF      0x04  /* Use ExprList.u.x.iOrderByCol */
#define SQLITE_ECEL_OMITREF  0x08  /* Omit if ExprList.u.x.iOrderByCol */







>










|







19559
19560
19561
19562
19563
19564
19565
19566
19567
19568
19569
19570
19571
19572
19573
19574
19575
19576
19577
19578
19579
19580
19581
19582
19583
19584
SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*);
#define ONEPASS_OFF      0        /* Use of ONEPASS not allowed */
#define ONEPASS_SINGLE   1        /* ONEPASS valid for a single row update */
#define ONEPASS_MULTI    2        /* ONEPASS is valid for multiple rows */
SQLITE_PRIVATE int sqlite3WhereUsesDeferredSeek(WhereInfo*);
SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int);
#endif
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
#define SQLITE_ECEL_DUP      0x01  /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR   0x02  /* Factor out constant terms */
#define SQLITE_ECEL_REF      0x04  /* Use ExprList.u.x.iOrderByCol */
#define SQLITE_ECEL_OMITREF  0x08  /* Omit if ExprList.u.x.iOrderByCol */
19225
19226
19227
19228
19229
19230
19231

19232
19233
19234
19235
19236
19237
19238
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int);
SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int);
SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int);
SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*);
SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *);
SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*);

SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr*);
SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);







>







19614
19615
19616
19617
19618
19619
19620
19621
19622
19623
19624
19625
19626
19627
19628
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int);
SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int);
SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int);
SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*);
SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *);
SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char*);
SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr*);
SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
19335
19336
19337
19338
19339
19340
19341

19342
19343
19344
19345
19346
19347
19348
SQLITE_PRIVATE   int sqlite3AuthReadCol(Parse*, const char *, const char *, int);
#else
# define sqlite3AuthRead(a,b,c,d)
# define sqlite3AuthCheck(a,b,c,d,e)    SQLITE_OK
# define sqlite3AuthContextPush(a,b,c)
# define sqlite3AuthContextPop(a)  ((void)(a))
#endif

SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);







>







19725
19726
19727
19728
19729
19730
19731
19732
19733
19734
19735
19736
19737
19738
19739
SQLITE_PRIVATE   int sqlite3AuthReadCol(Parse*, const char *, const char *, int);
#else
# define sqlite3AuthRead(a,b,c,d)
# define sqlite3AuthCheck(a,b,c,d,e)    SQLITE_OK
# define sqlite3AuthContextPush(a,b,c)
# define sqlite3AuthContextPop(a)  ((void)(a))
#endif
SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName);
SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
19383
19384
19385
19386
19387
19388
19389


19390
19391
19392
19393
19394
19395
19396
19397
19398
19399
19400
19401
19402
19403
19404
19405
19406
19407
19408
19409
/*
** The common case is for a varint to be a single byte.  They following
** macros handle the common case without a procedure call, but then call
** the procedure for larger varints.
*/
#define getVarint32(A,B)  \
  (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B)))


#define putVarint32(A,B)  \
  (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\
  sqlite3PutVarint((A),(B)))
#define getVarint    sqlite3GetVarint
#define putVarint    sqlite3PutVarint


SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int);
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);







>
>









|
|

|







19774
19775
19776
19777
19778
19779
19780
19781
19782
19783
19784
19785
19786
19787
19788
19789
19790
19791
19792
19793
19794
19795
19796
19797
19798
19799
19800
19801
19802
/*
** The common case is for a varint to be a single byte.  They following
** macros handle the common case without a procedure call, but then call
** the procedure for larger varints.
*/
#define getVarint32(A,B)  \
  (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B)))
#define getVarint32NR(A,B) \
  B=(u32)*(A);if(B>=0x80)sqlite3GetVarint32((A),(u32*)&(B))
#define putVarint32(A,B)  \
  (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\
  sqlite3PutVarint((A),(B)))
#define getVarint    sqlite3GetVarint
#define putVarint    sqlite3PutVarint


SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int);
SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
19418
19419
19420
19421
19422
19423
19424

19425
19426
19427
19428
19429
19430
19431
19432
19433
19434
#endif

SQLITE_PRIVATE const char *sqlite3ErrStr(int);
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);

SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);
SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*);
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*);







>
|
|
|







19811
19812
19813
19814
19815
19816
19817
19818
19819
19820
19821
19822
19823
19824
19825
19826
19827
19828
#endif

SQLITE_PRIVATE const char *sqlite3ErrStr(int);
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8);
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr);
SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr);
SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*);
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*);
19481
19482
19483
19484
19485
19486
19487
19488







19489
19490
19491
19492
19493
19494
19495
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int);
SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);







SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*);
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
SQLITE_PRIVATE int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);







|
>
>
>
>
>
>
>







19875
19876
19877
19878
19879
19880
19881
19882
19883
19884
19885
19886
19887
19888
19889
19890
19891
19892
19893
19894
19895
19896
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int);
SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
SQLITE_PRIVATE int sqlite3MatchEName(
  const struct ExprList_item*,
  const char*,
  const char*,
  const char*
);
SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*);
SQLITE_PRIVATE u8 sqlite3StrIHash(const char*);
SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*);
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
SQLITE_PRIVATE int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
19646
19647
19648
19649
19650
19651
19652
19653
19654
19655
19656
19657
19658
19659
19660
19661
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
SQLITE_PRIVATE void sqlite3ParserReset(Parse*);
#ifdef SQLITE_ENABLE_NORMALIZE
SQLITE_PRIVATE char *sqlite3Normalize(Vdbe*, const char*);
#endif
SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*);
SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse*,Expr*);
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
#ifndef SQLITE_OMIT_CTE







|
|







20047
20048
20049
20050
20051
20052
20053
20054
20055
20056
20057
20058
20059
20060
20061
20062
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
SQLITE_PRIVATE void sqlite3ParserReset(Parse*);
#ifdef SQLITE_ENABLE_NORMALIZE
SQLITE_PRIVATE char *sqlite3Normalize(Vdbe*, const char*);
#endif
SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*);
SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse*,const Expr*);
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, const Expr*, const 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
#ifndef SQLITE_OMIT_CTE
19953
19954
19955
19956
19957
19958
19959
19960
19961
19962
19963
19964
19965
19966
19967
** array. tolower() is used more often than toupper() by SQLite.
**
** Bit 0x40 is set if the character is non-alphanumeric and can be used in an 
** SQLite identifier.  Identifiers are alphanumerics, "_", "$", and any
** non-ASCII UTF character. Hence the test for whether or not a character is
** part of an identifier is 0x46.
*/
#ifdef SQLITE_ASCII
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 00..07    ........ */
  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /* 08..0f    ........ */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 10..17    ........ */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18..1f    ........ */
  0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80,  /* 20..27     !"#$%&' */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 28..2f    ()*+,-./ */







<







20354
20355
20356
20357
20358
20359
20360

20361
20362
20363
20364
20365
20366
20367
** array. tolower() is used more often than toupper() by SQLite.
**
** Bit 0x40 is set if the character is non-alphanumeric and can be used in an 
** SQLite identifier.  Identifiers are alphanumerics, "_", "$", and any
** non-ASCII UTF character. Hence the test for whether or not a character is
** part of an identifier is 0x46.
*/

SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 00..07    ........ */
  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /* 08..0f    ........ */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 10..17    ........ */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18..1f    ........ */
  0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80,  /* 20..27     !"#$%&' */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 28..2f    ()*+,-./ */
19991
19992
19993
19994
19995
19996
19997
19998
19999
20000
20001
20002
20003
20004
20005
20006
20007
20008
20009
20010
20011
20012
20013
20014
20015
20016
20017
20018
20019
20020
20021
20022
20023
20024
20025
20026
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d0..d7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d8..df    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e0..e7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e8..ef    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* f0..f7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};
#endif

/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
** compatibility for legacy applications, the URI filename capability is
** disabled by default.
**
** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled
** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options.
**
** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
** disabled. The default value may be changed by compiling with the
** SQLITE_USE_URI symbol defined.
**
** URI filenames are enabled by default if SQLITE_HAS_CODEC is
** enabled.
*/
#ifndef SQLITE_USE_URI
# ifdef SQLITE_HAS_CODEC
#  define SQLITE_USE_URI 1
# else
#  define SQLITE_USE_URI 0
# endif
#endif

/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
** that compile-time option is omitted.
*/
#if !defined(SQLITE_ALLOW_COVERING_INDEX_SCAN)







<











<
<
<


<
<
<
|
<







20391
20392
20393
20394
20395
20396
20397

20398
20399
20400
20401
20402
20403
20404
20405
20406
20407
20408



20409
20410



20411

20412
20413
20414
20415
20416
20417
20418
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d0..d7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d8..df    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e0..e7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e8..ef    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* f0..f7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};


/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
** compatibility for legacy applications, the URI filename capability is
** disabled by default.
**
** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled
** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options.
**
** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
** disabled. The default value may be changed by compiling with the
** SQLITE_USE_URI symbol defined.



*/
#ifndef SQLITE_USE_URI



# define SQLITE_USE_URI 0

#endif

/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
** that compile-time option is omitted.
*/
#if !defined(SQLITE_ALLOW_COVERING_INDEX_SCAN)
20056
20057
20058
20059
20060
20061
20062





20063
20064

20065



20066
20067
20068
20069
20070
20071
20072
/*
** The default lookaside-configuration, the format "SZ,N".  SZ is the
** number of bytes in each lookaside slot (should be a multiple of 8)
** and N is the number of slots.  The lookaside-configuration can be
** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE)
** or at run-time for an individual database connection using
** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE);





*/
#ifndef SQLITE_DEFAULT_LOOKASIDE

# define SQLITE_DEFAULT_LOOKASIDE 1200,100



#endif


/* The default maximum size of an in-memory database created using
** sqlite3_deserialize()
*/
#ifndef SQLITE_MEMDB_DEFAULT_MAXSIZE







>
>
>
>
>


>
|
>
>
>







20448
20449
20450
20451
20452
20453
20454
20455
20456
20457
20458
20459
20460
20461
20462
20463
20464
20465
20466
20467
20468
20469
20470
20471
20472
20473
/*
** The default lookaside-configuration, the format "SZ,N".  SZ is the
** number of bytes in each lookaside slot (should be a multiple of 8)
** and N is the number of slots.  The lookaside-configuration can be
** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE)
** or at run-time for an individual database connection using
** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE);
**
** With the two-size-lookaside enhancement, less lookaside is required.
** The default configuration of 1200,40 actually provides 30 1200-byte slots
** and 93 128-byte slots, which is more lookaside than is available
** using the older 1200,100 configuration without two-size-lookaside.
*/
#ifndef SQLITE_DEFAULT_LOOKASIDE
# ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
#   define SQLITE_DEFAULT_LOOKASIDE 1200,100  /* 120KB of memory */
# else
#   define SQLITE_DEFAULT_LOOKASIDE 1200,40   /* 48KB of memory */
# endif
#endif


/* The default maximum size of an in-memory database created using
** sqlite3_deserialize()
*/
#ifndef SQLITE_MEMDB_DEFAULT_MAXSIZE
20124
20125
20126
20127
20128
20129
20130
20131
20132
20133
20134
20135
20136
20137
20138
#ifdef SQLITE_ENABLE_DESERIALIZE
   SQLITE_MEMDB_DEFAULT_MAXSIZE,   /* mxMemdbSize */
#endif
#ifndef SQLITE_UNTESTABLE
   0,                         /* xTestCallback */
#endif
   0,                         /* bLocaltimeFault */
   0,                         /* bInternalFunctions */
   0x7ffffffe,                /* iOnceResetThreshold */
   SQLITE_DEFAULT_SORTERREF_SIZE,   /* szSorterRef */
   0,                         /* iPrngSeed */
};

/*
** Hash table for global functions - functions common to all







<







20525
20526
20527
20528
20529
20530
20531

20532
20533
20534
20535
20536
20537
20538
#ifdef SQLITE_ENABLE_DESERIALIZE
   SQLITE_MEMDB_DEFAULT_MAXSIZE,   /* mxMemdbSize */
#endif
#ifndef SQLITE_UNTESTABLE
   0,                         /* xTestCallback */
#endif
   0,                         /* bLocaltimeFault */

   0x7ffffffe,                /* iOnceResetThreshold */
   SQLITE_DEFAULT_SORTERREF_SIZE,   /* szSorterRef */
   0,                         /* iPrngSeed */
};

/*
** Hash table for global functions - functions common to all
20621
20622
20623
20624
20625
20626
20627

20628
20629
20630
20631
20632
20633
20634
20635
20636
20637
  int rcApp;              /* errcode set by sqlite3_result_error_code() */
  u32 nWrite;             /* Number of write operations that have occurred */
#endif
  u16 nResColumn;         /* Number of columns in one row of the result set */
  u8 errorAction;         /* Recovery action to do in case of an error */
  u8 minWriteFileFormat;  /* Minimum file format for writable database files */
  u8 prepFlags;           /* SQLITE_PREPARE_* flags */

  bft expired:2;          /* 1: recompile VM immediately  2: when convenient */
  bft explain:2;          /* True if EXPLAIN present on SQL command */
  bft doingRerun:1;       /* True if rerunning after an auto-reprepare */
  bft changeCntOn:1;      /* True to update the change-counter */
  bft runOnlyOnce:1;      /* Automatically expire on reset */
  bft usesStmtJournal:1;  /* True if uses a statement journal */
  bft readOnly:1;         /* True for statements that do not write */
  bft bIsReader:1;        /* True for statements that read */
  yDbMask btreeMask;      /* Bitmask of db->aDb[] entries referenced */
  yDbMask lockMask;       /* Subset of btreeMask that requires a lock */







>


<







21021
21022
21023
21024
21025
21026
21027
21028
21029
21030

21031
21032
21033
21034
21035
21036
21037
  int rcApp;              /* errcode set by sqlite3_result_error_code() */
  u32 nWrite;             /* Number of write operations that have occurred */
#endif
  u16 nResColumn;         /* Number of columns in one row of the result set */
  u8 errorAction;         /* Recovery action to do in case of an error */
  u8 minWriteFileFormat;  /* Minimum file format for writable database files */
  u8 prepFlags;           /* SQLITE_PREPARE_* flags */
  u8 doingRerun;          /* True if rerunning after an auto-reprepare */
  bft expired:2;          /* 1: recompile VM immediately  2: when convenient */
  bft explain:2;          /* True if EXPLAIN present on SQL command */

  bft changeCntOn:1;      /* True to update the change-counter */
  bft runOnlyOnce:1;      /* Automatically expire on reset */
  bft usesStmtJournal:1;  /* True if uses a statement journal */
  bft readOnly:1;         /* True for statements that do not write */
  bft bIsReader:1;        /* True for statements that read */
  yDbMask btreeMask;      /* Bitmask of db->aDb[] entries referenced */
  yDbMask lockMask;       /* Subset of btreeMask that requires a lock */
20686
20687
20688
20689
20690
20691
20692

20693
20694
20695
20696
20697
20698
20699

/*
** Function prototypes
*/
SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);

SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);







>







21086
21087
21088
21089
21090
21091
21092
21093
21094
21095
21096
21097
21098
21099
21100

/*
** Function prototypes
*/
SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
20732
20733
20734
20735
20736
20737
20738
20739
20740

20741
20742
20743
20744
20745
20746
20747
SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*);
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*);
SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull);
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);

SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef SQLITE_OMIT_WINDOWFUNC
SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
#endif
#ifndef SQLITE_OMIT_EXPLAIN
SQLITE_PRIVATE const char *sqlite3OpcodeName(int);







|

>







21133
21134
21135
21136
21137
21138
21139
21140
21141
21142
21143
21144
21145
21146
21147
21148
21149
SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*);
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*);
SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull);
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem*,u8,u8);
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(BtCursor*,u32,Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef SQLITE_OMIT_WINDOWFUNC
SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
#endif
#ifndef SQLITE_OMIT_EXPLAIN
SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
20798
20799
20800
20801
20802
20803
20804
20805
20806
20807
20808
20809
20810
20811
20812
SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
#else
# define sqlite3VdbeCheckFk(p,i) 0
#endif

#ifdef SQLITE_DEBUG
SQLITE_PRIVATE   void sqlite3VdbePrintSql(Vdbe*);
SQLITE_PRIVATE   void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
#endif
#ifndef SQLITE_OMIT_UTF16
SQLITE_PRIVATE   int sqlite3VdbeMemTranslate(Mem*, u8);
SQLITE_PRIVATE   int sqlite3VdbeMemHandleBom(Mem *pMem);
#endif

#ifndef SQLITE_OMIT_INCRBLOB







|







21200
21201
21202
21203
21204
21205
21206
21207
21208
21209
21210
21211
21212
21213
21214
SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
#else
# define sqlite3VdbeCheckFk(p,i) 0
#endif

#ifdef SQLITE_DEBUG
SQLITE_PRIVATE   void sqlite3VdbePrintSql(Vdbe*);
SQLITE_PRIVATE   void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr);
#endif
#ifndef SQLITE_OMIT_UTF16
SQLITE_PRIVATE   int sqlite3VdbeMemTranslate(Mem*, u8);
SQLITE_PRIVATE   int sqlite3VdbeMemHandleBom(Mem *pMem);
#endif

#ifndef SQLITE_OMIT_INCRBLOB
20990
20991
20992
20993
20994
20995
20996




20997
20998
20999
21000
21001
21002
21003

/*
** Count the number of slots of lookaside memory that are outstanding
*/
SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
  u32 nInit = countLookasideSlots(db->lookaside.pInit);
  u32 nFree = countLookasideSlots(db->lookaside.pFree);




  if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
  return db->lookaside.nSlot - (nInit+nFree);
}

/*
** Query status information for a single database connection
*/







>
>
>
>







21392
21393
21394
21395
21396
21397
21398
21399
21400
21401
21402
21403
21404
21405
21406
21407
21408
21409

/*
** Count the number of slots of lookaside memory that are outstanding
*/
SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
  u32 nInit = countLookasideSlots(db->lookaside.pInit);
  u32 nFree = countLookasideSlots(db->lookaside.pFree);
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
  nInit += countLookasideSlots(db->lookaside.pSmallInit);
  nFree += countLookasideSlots(db->lookaside.pSmallFree);
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
  if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
  return db->lookaside.nSlot - (nInit+nFree);
}

/*
** Query status information for a single database connection
*/
21022
21023
21024
21025
21026
21027
21028









21029
21030
21031
21032
21033
21034
21035
        LookasideSlot *p = db->lookaside.pFree;
        if( p ){
          while( p->pNext ) p = p->pNext;
          p->pNext = db->lookaside.pInit;
          db->lookaside.pInit = db->lookaside.pFree;
          db->lookaside.pFree = 0;
        }









      }
      break;
    }

    case SQLITE_DBSTATUS_LOOKASIDE_HIT:
    case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
    case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {







>
>
>
>
>
>
>
>
>







21428
21429
21430
21431
21432
21433
21434
21435
21436
21437
21438
21439
21440
21441
21442
21443
21444
21445
21446
21447
21448
21449
21450
        LookasideSlot *p = db->lookaside.pFree;
        if( p ){
          while( p->pNext ) p = p->pNext;
          p->pNext = db->lookaside.pInit;
          db->lookaside.pInit = db->lookaside.pFree;
          db->lookaside.pFree = 0;
        }
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
        p = db->lookaside.pSmallFree;
        if( p ){
          while( p->pNext ) p = p->pNext;
          p->pNext = db->lookaside.pSmallInit;
          db->lookaside.pSmallInit = db->lookaside.pSmallFree;
          db->lookaside.pSmallFree = 0;
        }
#endif
      }
      break;
    }

    case SQLITE_DBSTATUS_LOOKASIDE_HIT:
    case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
    case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
21806
21807
21808
21809
21810
21811
21812
21813
21814
21815
21816
21817
21818
21819
21820
21821
21822
21823
21824
21825
static const struct {
  u8 eType;           /* Transformation type code */
  u8 nName;           /* Length of th name */
  char *zName;        /* Name of the transformation */
  double rLimit;      /* Maximum NNN value for this transform */
  double rXform;      /* Constant used for this transform */
} aXformType[] = {
  { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
  { 0, 6, "minute", 7737817680.0,   86400000.0/(24.0*60.0)      },
  { 0, 4, "hour",   128963628.0,    86400000.0/24.0             },
  { 0, 3, "day",    5373485.0,      86400000.0                  },
  { 1, 5, "month",  176546.0,       30.0*86400000.0             },
  { 2, 4, "year",   14713.0,        365.0*86400000.0            },
};

/*
** Process a modifier to a date-time stamp.  The modifiers are
** as follows:
**
**     NNN days







|
|
|
|
|
|







22221
22222
22223
22224
22225
22226
22227
22228
22229
22230
22231
22232
22233
22234
22235
22236
22237
22238
22239
22240
static const struct {
  u8 eType;           /* Transformation type code */
  u8 nName;           /* Length of th name */
  char *zName;        /* Name of the transformation */
  double rLimit;      /* Maximum NNN value for this transform */
  double rXform;      /* Constant used for this transform */
} aXformType[] = {
  { 0, 6, "second", 464269060800.0, 1000.0         },
  { 0, 6, "minute", 7737817680.0,   60000.0        },
  { 0, 4, "hour",   128963628.0,    3600000.0      },
  { 0, 3, "day",    5373485.0,      86400000.0     },
  { 1, 5, "month",  176546.0,       2592000000.0   },
  { 2, 4, "year",   14713.0,        31536000000.0  },
};

/*
** Process a modifier to a date-time stamp.  The modifiers are
** as follows:
**
**     NNN days
21873
21874
21875
21876
21877
21878
21879
21880
21881
21882
21883
21884
21885
21886
21887
      ** Treat the current value of p->s as the number of
      ** seconds since 1970.  Convert to a real julian day number.
      */
      if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
        r = p->s*1000.0 + 210866760000000.0;
        if( r>=0.0 && r<464269060800000.0 ){
          clearYMD_HMS_TZ(p);
          p->iJD = (sqlite3_int64)r;
          p->validJD = 1;
          p->rawS = 0;
          rc = 0;
        }
      }
#ifndef SQLITE_OMIT_LOCALTIME
      else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){







|







22288
22289
22290
22291
22292
22293
22294
22295
22296
22297
22298
22299
22300
22301
22302
      ** Treat the current value of p->s as the number of
      ** seconds since 1970.  Convert to a real julian day number.
      */
      if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
        r = p->s*1000.0 + 210866760000000.0;
        if( r>=0.0 && r<464269060800000.0 ){
          clearYMD_HMS_TZ(p);
          p->iJD = (sqlite3_int64)(r + 0.5);
          p->validJD = 1;
          p->rawS = 0;
          rc = 0;
        }
      }
#ifndef SQLITE_OMIT_LOCALTIME
      else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
22652
22653
22654
22655
22656
22657
22658
22659
22660
22661
22662
22663
22664
22665
22666
){
  int rc;
  DO_OS_MALLOC_TEST(0);
  /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
  ** down into the VFS layer.  Some SQLITE_OPEN_ flags (for example,
  ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
  ** reaching the VFS. */
  rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut);
  assert( rc==SQLITE_OK || pFile->pMethods==0 );
  return rc;
}
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  DO_OS_MALLOC_TEST(0);
  assert( dirSync==0 || dirSync==1 );
  return pVfs->xDelete(pVfs, zPath, dirSync);







|







23067
23068
23069
23070
23071
23072
23073
23074
23075
23076
23077
23078
23079
23080
23081
){
  int rc;
  DO_OS_MALLOC_TEST(0);
  /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
  ** down into the VFS layer.  Some SQLITE_OPEN_ flags (for example,
  ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
  ** reaching the VFS. */
  rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
  assert( rc==SQLITE_OK || pFile->pMethods==0 );
  return rc;
}
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  DO_OS_MALLOC_TEST(0);
  assert( dirSync==0 || dirSync==1 );
  return pVfs->xDelete(pVfs, zPath, dirSync);
25371
25372
25373
25374
25375
25376
25377

25378
25379
25380
25381
25382
25383
25384
  assert( sqlite3GlobalConfig.mutex.xMutexInit );
  rc = sqlite3GlobalConfig.mutex.xMutexInit();

#ifdef SQLITE_DEBUG
  GLOBAL(int, mutexIsInit) = 1;
#endif


  return rc;
}

/*
** Shutdown the mutex system. This call frees resources allocated by
** sqlite3MutexInit().
*/







>







25786
25787
25788
25789
25790
25791
25792
25793
25794
25795
25796
25797
25798
25799
25800
  assert( sqlite3GlobalConfig.mutex.xMutexInit );
  rc = sqlite3GlobalConfig.mutex.xMutexInit();

#ifdef SQLITE_DEBUG
  GLOBAL(int, mutexIsInit) = 1;
#endif

  sqlite3MemoryBarrier();
  return rc;
}

/*
** Shutdown the mutex system. This call frees resources allocated by
** sqlite3MutexInit().
*/
27118
27119
27120
27121
27122
27123
27124







27125
27126
27127
27128
27129

27130
27131
27132
27133
27134
27135
27136

27137





27138

27139

27140
27141
27142



27143
27144
27145
27146
27147
27148
27149
/*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/
SQLITE_PRIVATE int sqlite3MallocSize(void *p){
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return sqlite3GlobalConfig.m.xSize(p);







}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
  assert( p!=0 );
  if( db==0 || !isLookaside(db,p) ){
#ifdef SQLITE_DEBUG

    if( db==0 ){
      assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
      assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    }else{
      assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
    }

#endif





    return sqlite3GlobalConfig.m.xSize(p);

  }else{

    assert( sqlite3_mutex_held(db->mutex) );
    return db->lookaside.szTrue;
  }



}
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
  assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
}








>
>
>
>
>
>
>



<

>







>

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







27534
27535
27536
27537
27538
27539
27540
27541
27542
27543
27544
27545
27546
27547
27548
27549
27550

27551
27552
27553
27554
27555
27556
27557
27558
27559
27560
27561
27562
27563
27564
27565
27566
27567
27568
27569
27570
27571
27572
27573
27574
27575
27576
27577
27578
27579
27580
27581
27582
27583
/*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/
SQLITE_PRIVATE int sqlite3MallocSize(void *p){
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return sqlite3GlobalConfig.m.xSize(p);
}
static int lookasideMallocSize(sqlite3 *db, void *p){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE    
  return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL;
#else
  return db->lookaside.szTrue;
#endif  
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
  assert( p!=0 );

#ifdef SQLITE_DEBUG
  if( db==0 || !isLookaside(db,p) ){
    if( db==0 ){
      assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
      assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    }else{
      assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
    }
  }
#endif
  if( db ){
    if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
      if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
        assert( sqlite3_mutex_held(db->mutex) );
        return LOOKASIDE_SMALL;
      }
#endif
      if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
        assert( sqlite3_mutex_held(db->mutex) );
        return db->lookaside.szTrue;
      }
    }
  }
  return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
  assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
}

27182
27183
27184
27185
27186
27187
27188
27189


27190
27191
27192









27193
27194
27195
27196
27197

27198
27199
27200
27201
27202
27203
27204
  assert( db==0 || sqlite3_mutex_held(db->mutex) );
  assert( p!=0 );
  if( db ){
    if( db->pnBytesFreed ){
      measureAllocationSize(db, p);
      return;
    }
    if( isLookaside(db, p) ){


      LookasideSlot *pBuf = (LookasideSlot*)p;
#ifdef SQLITE_DEBUG
      /* Trash all content in the buffer being freed */









      memset(p, 0xaa, db->lookaside.szTrue);
#endif
      pBuf->pNext = db->lookaside.pFree;
      db->lookaside.pFree = pBuf;
      return;

    }
  }
  assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
  assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
  assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
  sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
  sqlite3_free(p);







|
>
>
|

|
>
>
>
>
>
>
>
>
>
|

|
|
|
>







27616
27617
27618
27619
27620
27621
27622
27623
27624
27625
27626
27627
27628
27629
27630
27631
27632
27633
27634
27635
27636
27637
27638
27639
27640
27641
27642
27643
27644
27645
27646
27647
27648
27649
27650
  assert( db==0 || sqlite3_mutex_held(db->mutex) );
  assert( p!=0 );
  if( db ){
    if( db->pnBytesFreed ){
      measureAllocationSize(db, p);
      return;
    }
    if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
      if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
        LookasideSlot *pBuf = (LookasideSlot*)p;
#ifdef SQLITE_DEBUG
        memset(p, 0xaa, LOOKASIDE_SMALL);  /* Trash freed content */
#endif
        pBuf->pNext = db->lookaside.pSmallFree;
        db->lookaside.pSmallFree = pBuf;
        return;
      }
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
      if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
        LookasideSlot *pBuf = (LookasideSlot*)p;
#ifdef SQLITE_DEBUG
        memset(p, 0xaa, db->lookaside.szTrue);  /* Trash freed content */
#endif
        pBuf->pNext = db->lookaside.pFree;
        db->lookaside.pFree = pBuf;
        return;
      }
    }
  }
  assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
  assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
  assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
  sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
  sqlite3_free(p);
27347
27348
27349
27350
27351
27352
27353
27354




27355
27356




27357

27358







27359
27360
27361
27362
27363
27364
27365
SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
#ifndef SQLITE_OMIT_LOOKASIDE
  LookasideSlot *pBuf;
  assert( db!=0 );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( db->pnBytesFreed==0 );
  if( n>db->lookaside.sz ){
    if( db->lookaside.bDisable ){




      return db->mallocFailed ? 0 : dbMallocRawFinish(db, n);
    }




    db->lookaside.anStat[1]++;

  }else if( (pBuf = db->lookaside.pFree)!=0 ){







    db->lookaside.pFree = pBuf->pNext;
    db->lookaside.anStat[0]++;
    return (void*)pBuf;
  }else if( (pBuf = db->lookaside.pInit)!=0 ){
    db->lookaside.pInit = pBuf->pNext;
    db->lookaside.anStat[0]++;
    return (void*)pBuf;







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







27793
27794
27795
27796
27797
27798
27799
27800
27801
27802
27803
27804
27805
27806
27807
27808
27809
27810
27811
27812
27813
27814
27815
27816
27817
27818
27819
27820
27821
27822
27823
27824
27825
27826
27827
SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
#ifndef SQLITE_OMIT_LOOKASIDE
  LookasideSlot *pBuf;
  assert( db!=0 );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( db->pnBytesFreed==0 );
  if( n>db->lookaside.sz ){
    if( !db->lookaside.bDisable ){
      db->lookaside.anStat[1]++;      
    }else if( db->mallocFailed ){
      return 0;
    }
    return dbMallocRawFinish(db, n);
  }
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
  if( n<=LOOKASIDE_SMALL ){
    if( (pBuf = db->lookaside.pSmallFree)!=0 ){
      db->lookaside.pSmallFree = pBuf->pNext;
      db->lookaside.anStat[0]++;
      return (void*)pBuf;
    }else if( (pBuf = db->lookaside.pSmallInit)!=0 ){
      db->lookaside.pSmallInit = pBuf->pNext;
      db->lookaside.anStat[0]++;
      return (void*)pBuf;
    }
  }
#endif
  if( (pBuf = db->lookaside.pFree)!=0 ){
    db->lookaside.pFree = pBuf->pNext;
    db->lookaside.anStat[0]++;
    return (void*)pBuf;
  }else if( (pBuf = db->lookaside.pInit)!=0 ){
    db->lookaside.pInit = pBuf->pNext;
    db->lookaside.anStat[0]++;
    return (void*)pBuf;
27384
27385
27386
27387
27388
27389
27390







27391


27392
27393
27394
27395
27396
27397
27398
27399
27400
27401
27402
27403
27404
27405
27406
27407
27408
27409
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag in the connection object.
*/
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
  assert( db!=0 );
  if( p==0 ) return sqlite3DbMallocRawNN(db, n);
  assert( sqlite3_mutex_held(db->mutex) );







  if( isLookaside(db,p) && n<=db->lookaside.szTrue ) return p;


  return dbReallocFinish(db, p, n);
}
static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
  void *pNew = 0;
  assert( db!=0 );
  assert( p!=0 );
  if( db->mallocFailed==0 ){
    if( isLookaside(db, p) ){
      pNew = sqlite3DbMallocRawNN(db, n);
      if( pNew ){
        memcpy(pNew, p, db->lookaside.szTrue);
        sqlite3DbFree(db, p);
      }
    }else{
      assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
      pNew = sqlite3_realloc64(p, n);







>
>
>
>
>
>
>
|
>
>










|







27846
27847
27848
27849
27850
27851
27852
27853
27854
27855
27856
27857
27858
27859
27860
27861
27862
27863
27864
27865
27866
27867
27868
27869
27870
27871
27872
27873
27874
27875
27876
27877
27878
27879
27880
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag in the connection object.
*/
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
  assert( db!=0 );
  if( p==0 ) return sqlite3DbMallocRawNN(db, n);
  assert( sqlite3_mutex_held(db->mutex) );
  if( ((uptr)p)<(uptr)db->lookaside.pEnd ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
    if( ((uptr)p)>=(uptr)db->lookaside.pMiddle ){
      if( n<=LOOKASIDE_SMALL ) return p;
    }else
#endif
    if( ((uptr)p)>=(uptr)db->lookaside.pStart ){
      if( n<=db->lookaside.szTrue ) return p;
    }
  }
  return dbReallocFinish(db, p, n);
}
static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
  void *pNew = 0;
  assert( db!=0 );
  assert( p!=0 );
  if( db->mallocFailed==0 ){
    if( isLookaside(db, p) ){
      pNew = sqlite3DbMallocRawNN(db, n);
      if( pNew ){
        memcpy(pNew, p, lookasideMallocSize(db, p));
        sqlite3DbFree(db, p);
      }
    }else{
      assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
      pNew = sqlite3_realloc64(p, n);
27492
27493
27494
27495
27496
27497
27498
27499
27500
27501
27502
27503
27504
27505
27506
27507
27508
27509
27510
27511
27512
27513
27514
27515
27516
27517
27518
27519
27520
27521
27522
27523
27524
27525
** temporarily disable the lookaside memory allocator and interrupt
** any running VDBEs.
*/
SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
  if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
    db->mallocFailed = 1;
    if( db->nVdbeExec>0 ){
      db->u1.isInterrupted = 1;
    }
    DisableLookaside;
    if( db->pParse ){
      db->pParse->rc = SQLITE_NOMEM_BKPT;
    }
  }
}

/*
** This routine reactivates the memory allocator and clears the
** db->mallocFailed flag as necessary.
**
** The memory allocator is not restarted if there are running
** VDBEs.
*/
SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){
  if( db->mallocFailed && db->nVdbeExec==0 ){
    db->mallocFailed = 0;
    db->u1.isInterrupted = 0;
    assert( db->lookaside.bDisable>0 );
    EnableLookaside;
  }
}

/*
** Take actions at the end of an API call to indicate an OOM error







|


















|







27963
27964
27965
27966
27967
27968
27969
27970
27971
27972
27973
27974
27975
27976
27977
27978
27979
27980
27981
27982
27983
27984
27985
27986
27987
27988
27989
27990
27991
27992
27993
27994
27995
27996
** temporarily disable the lookaside memory allocator and interrupt
** any running VDBEs.
*/
SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
  if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
    db->mallocFailed = 1;
    if( db->nVdbeExec>0 ){
      AtomicStore(&db->u1.isInterrupted, 1);
    }
    DisableLookaside;
    if( db->pParse ){
      db->pParse->rc = SQLITE_NOMEM_BKPT;
    }
  }
}

/*
** This routine reactivates the memory allocator and clears the
** db->mallocFailed flag as necessary.
**
** The memory allocator is not restarted if there are running
** VDBEs.
*/
SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){
  if( db->mallocFailed && db->nVdbeExec==0 ){
    db->mallocFailed = 0;
    AtomicStore(&db->u1.isInterrupted, 0);
    assert( db->lookaside.bDisable>0 );
    EnableLookaside;
  }
}

/*
** Take actions at the end of an API call to indicate an OOM error
28961
28962
28963
28964
28965
28966
28967
28968
28969
28970
28971
28972
28973
28974
28975
      const struct Cte *pCte = &pWith->a[i];
      sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
      sqlite3_str_appendf(&x, "%s", pCte->zName);
      if( pCte->pCols && pCte->pCols->nExpr>0 ){
        char cSep = '(';
        int j;
        for(j=0; j<pCte->pCols->nExpr; j++){
          sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zName);
          cSep = ',';
        }
        sqlite3_str_appendf(&x, ")");
      }
      sqlite3_str_appendf(&x, " AS");
      sqlite3StrAccumFinish(&x);
      sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);







|







29432
29433
29434
29435
29436
29437
29438
29439
29440
29441
29442
29443
29444
29445
29446
      const struct Cte *pCte = &pWith->a[i];
      sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
      sqlite3_str_appendf(&x, "%s", pCte->zName);
      if( pCte->pCols && pCte->pCols->nExpr>0 ){
        char cSep = '(';
        int j;
        for(j=0; j<pCte->pCols->nExpr; j++){
          sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName);
          cSep = ',';
        }
        sqlite3_str_appendf(&x, ")");
      }
      sqlite3_str_appendf(&x, " AS");
      sqlite3StrAccumFinish(&x);
      sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
28993
28994
28995
28996
28997
28998
28999
29000
29001
29002
29003
29004
29005
29006
29007
29008



29009
29010
29011
29012
29013
29014
29015
    sqlite3_str_appendf(&x, "{%d:*}", pItem->iCursor);
    if( pItem->zDatabase ){
      sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
    }else if( pItem->zName ){
      sqlite3_str_appendf(&x, " %s", pItem->zName);
    }
    if( pItem->pTab ){
      sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p",
           pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab);
    }
    if( pItem->zAlias ){
      sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias);
    }
    if( pItem->fg.jointype & JT_LEFT ){
      sqlite3_str_appendf(&x, " LEFT-JOIN");
    }



    sqlite3StrAccumFinish(&x);
    sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); 
    if( pItem->pSelect ){
      sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
    }
    if( pItem->fg.isTabFunc ){
      sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");







|
|







>
>
>







29464
29465
29466
29467
29468
29469
29470
29471
29472
29473
29474
29475
29476
29477
29478
29479
29480
29481
29482
29483
29484
29485
29486
29487
29488
29489
    sqlite3_str_appendf(&x, "{%d:*}", pItem->iCursor);
    if( pItem->zDatabase ){
      sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
    }else if( pItem->zName ){
      sqlite3_str_appendf(&x, " %s", pItem->zName);
    }
    if( pItem->pTab ){
      sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx",
           pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed);
    }
    if( pItem->zAlias ){
      sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias);
    }
    if( pItem->fg.jointype & JT_LEFT ){
      sqlite3_str_appendf(&x, " LEFT-JOIN");
    }
    if( pItem->fg.fromDDL ){
      sqlite3_str_appendf(&x, " DDL");
    }
    sqlite3StrAccumFinish(&x);
    sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); 
    if( pItem->pSelect ){
      sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
    }
    if( pItem->fg.isTabFunc ){
      sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
29250
29251
29252
29253
29254
29255
29256
29257
29258
29259
29260
29261
29262
29263
29264
29265

29266
29267

29268
29269


29270

29271

29272

29273
29274
29275
29276
29277
29278
29279

/*
** Generate a human-readable explanation of an expression tree.
*/
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
  const char *zBinOp = 0;   /* Binary operator */
  const char *zUniOp = 0;   /* Unary operator */
  char zFlgs[60];
  pView = sqlite3TreeViewPush(pView, moreToFollow);
  if( pExpr==0 ){
    sqlite3TreeViewLine(pView, "nil");
    sqlite3TreeViewPop(pView);
    return;
  }
  if( pExpr->flags || pExpr->affExpr ){
    if( ExprHasProperty(pExpr, EP_FromJoin) ){

      sqlite3_snprintf(sizeof(zFlgs),zFlgs,"  fg.af=%x.%c iRJT=%d",
                       pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n',

                       pExpr->iRightJoinTable);
    }else{


      sqlite3_snprintf(sizeof(zFlgs),zFlgs,"  fg.af=%x.%c",

                       pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');

    }

  }else{
    zFlgs[0] = 0;
  }
  switch( pExpr->op ){
    case TK_AGG_COLUMN: {
      sqlite3TreeViewLine(pView, "AGG{%d:%d}%s",
            pExpr->iTable, pExpr->iColumn, zFlgs);







|






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

>







29724
29725
29726
29727
29728
29729
29730
29731
29732
29733
29734
29735
29736
29737
29738
29739
29740
29741
29742
29743
29744

29745
29746
29747
29748
29749
29750
29751
29752
29753
29754
29755
29756
29757
29758
29759

/*
** Generate a human-readable explanation of an expression tree.
*/
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
  const char *zBinOp = 0;   /* Binary operator */
  const char *zUniOp = 0;   /* Unary operator */
  char zFlgs[200];
  pView = sqlite3TreeViewPush(pView, moreToFollow);
  if( pExpr==0 ){
    sqlite3TreeViewLine(pView, "nil");
    sqlite3TreeViewPop(pView);
    return;
  }
  if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){
    StrAccum x;
    sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0);
    sqlite3_str_appendf(&x, " fg.af=%x.%c",
      pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
    if( ExprHasProperty(pExpr, EP_FromJoin) ){
      sqlite3_str_appendf(&x, " iRJT=%d", pExpr->iRightJoinTable);

    }
    if( ExprHasProperty(pExpr, EP_FromDDL) ){
      sqlite3_str_appendf(&x, " DDL");
    }
    if( ExprHasVVAProperty(pExpr, EP_Immutable) ){
      sqlite3_str_appendf(&x, " IMMUTABLE");
    }
    sqlite3StrAccumFinish(&x);
  }else{
    zFlgs[0] = 0;
  }
  switch( pExpr->op ){
    case TK_AGG_COLUMN: {
      sqlite3TreeViewLine(pView, "AGG{%d:%d}%s",
            pExpr->iTable, pExpr->iColumn, zFlgs);
29287
29288
29289
29290
29291
29292
29293
29294
29295

29296
29297
29298
29299
29300
29301
29302
          sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x",pExpr->op2);
        }else{
          zOp2[0] = 0;
        }
        sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s",
                                    pExpr->iColumn, zFlgs, zOp2);
      }else{
        sqlite3TreeViewLine(pView, "{%d:%d}%s",
                             pExpr->iTable, pExpr->iColumn, zFlgs);

      }
      if( ExprHasProperty(pExpr, EP_FixedCol) ){
        sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
      }
      break;
    }
    case TK_INTEGER: {







|
|
>







29767
29768
29769
29770
29771
29772
29773
29774
29775
29776
29777
29778
29779
29780
29781
29782
29783
          sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x",pExpr->op2);
        }else{
          zOp2[0] = 0;
        }
        sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s",
                                    pExpr->iColumn, zFlgs, zOp2);
      }else{
        sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s",
                        pExpr->iTable, pExpr->iColumn,
                        pExpr->y.pTab, zFlgs);
      }
      if( ExprHasProperty(pExpr, EP_FixedCol) ){
        sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
      }
      break;
    }
    case TK_INTEGER: {
29370
29371
29372
29373
29374
29375
29376

29377
29378
29379
29380
29381
29382
29383
    case TK_BITAND:  zBinOp = "BITAND"; break;
    case TK_BITOR:   zBinOp = "BITOR";  break;
    case TK_SLASH:   zBinOp = "DIV";    break;
    case TK_LSHIFT:  zBinOp = "LSHIFT"; break;
    case TK_RSHIFT:  zBinOp = "RSHIFT"; break;
    case TK_CONCAT:  zBinOp = "CONCAT"; break;
    case TK_DOT:     zBinOp = "DOT";    break;


    case TK_UMINUS:  zUniOp = "UMINUS"; break;
    case TK_UPLUS:   zUniOp = "UPLUS";  break;
    case TK_BITNOT:  zUniOp = "BITNOT"; break;
    case TK_NOT:     zUniOp = "NOT";    break;
    case TK_ISNULL:  zUniOp = "ISNULL"; break;
    case TK_NOTNULL: zUniOp = "NOTNULL"; break;







>







29851
29852
29853
29854
29855
29856
29857
29858
29859
29860
29861
29862
29863
29864
29865
    case TK_BITAND:  zBinOp = "BITAND"; break;
    case TK_BITOR:   zBinOp = "BITOR";  break;
    case TK_SLASH:   zBinOp = "DIV";    break;
    case TK_LSHIFT:  zBinOp = "LSHIFT"; break;
    case TK_RSHIFT:  zBinOp = "RSHIFT"; break;
    case TK_CONCAT:  zBinOp = "CONCAT"; break;
    case TK_DOT:     zBinOp = "DOT";    break;
    case TK_LIMIT:   zBinOp = "LIMIT";  break;

    case TK_UMINUS:  zUniOp = "UMINUS"; break;
    case TK_UPLUS:   zUniOp = "UPLUS";  break;
    case TK_BITNOT:  zUniOp = "BITNOT"; break;
    case TK_NOT:     zUniOp = "NOT";    break;
    case TK_ISNULL:  zUniOp = "ISNULL"; break;
    case TK_NOTNULL: zUniOp = "NOTNULL"; break;
29420
29421
29422
29423
29424
29425
29426
29427
29428
29429
29430
29431
29432
29433
29434
      Window *pWin;
      if( ExprHasProperty(pExpr, EP_TokenOnly) ){
        pFarg = 0;
        pWin = 0;
      }else{
        pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
        pWin = pExpr->y.pWin;
#else
        pWin = 0;
#endif 
      }
      if( pExpr->op==TK_AGG_FUNCTION ){
        sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
                             pExpr->op2, pExpr->u.zToken, zFlgs);







|







29902
29903
29904
29905
29906
29907
29908
29909
29910
29911
29912
29913
29914
29915
29916
      Window *pWin;
      if( ExprHasProperty(pExpr, EP_TokenOnly) ){
        pFarg = 0;
        pWin = 0;
      }else{
        pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
        pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;
#else
        pWin = 0;
#endif 
      }
      if( pExpr->op==TK_AGG_FUNCTION ){
        sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
                             pExpr->op2, pExpr->u.zToken, zFlgs);
29582
29583
29584
29585
29586
29587
29588
29589
29590

29591
29592
29593
29594
29595
29596
29597
  if( pList==0 ){
    sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
  }else{
    int i;
    sqlite3TreeViewLine(pView, "%s", zLabel);
    for(i=0; i<pList->nExpr; i++){
      int j = pList->a[i].u.x.iOrderByCol;
      char *zName = pList->a[i].zName;
      int moreToFollow = i<pList->nExpr - 1;

      if( j || zName ){
        sqlite3TreeViewPush(pView, moreToFollow);
        moreToFollow = 0;
        sqlite3TreeViewLine(pView, 0);
        if( zName ){
          fprintf(stdout, "AS %s ", zName);
        }







|

>







30064
30065
30066
30067
30068
30069
30070
30071
30072
30073
30074
30075
30076
30077
30078
30079
30080
  if( pList==0 ){
    sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
  }else{
    int i;
    sqlite3TreeViewLine(pView, "%s", zLabel);
    for(i=0; i<pList->nExpr; i++){
      int j = pList->a[i].u.x.iOrderByCol;
      char *zName = pList->a[i].zEName;
      int moreToFollow = i<pList->nExpr - 1;
      if( pList->a[i].eEName!=ENAME_NAME ) zName = 0;
      if( j || zName ){
        sqlite3TreeViewPush(pView, moreToFollow);
        moreToFollow = 0;
        sqlite3TreeViewLine(pView, 0);
        if( zName ){
          fprintf(stdout, "AS %s ", zName);
        }
30140
30141
30142
30143
30144
30145
30146
30147
30148
30149
30150
30151
30152
30153
30154
30155
30156
30157
30158
30159
30160
30161
30162
30163
30164
30165
30166
30167
30168
30169
30170
30171
30172
30173
    *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03));              \
    *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0));  \
    *zOut++ = (u8)(0x00DC + ((c>>8)&0x03));                         \
    *zOut++ = (u8)(c&0x00FF);                                       \
  }                                                                 \
}

#define READ_UTF16LE(zIn, TERM, c){                                   \
  c = (*zIn++);                                                       \
  c += ((*zIn++)<<8);                                                 \
  if( c>=0xD800 && c<0xE000 && TERM ){                                \
    int c2 = (*zIn++);                                                \
    c2 += ((*zIn++)<<8);                                              \
    c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);   \
  }                                                                   \
}

#define READ_UTF16BE(zIn, TERM, c){                                   \
  c = ((*zIn++)<<8);                                                  \
  c += (*zIn++);                                                      \
  if( c>=0xD800 && c<0xE000 && TERM ){                                \
    int c2 = ((*zIn++)<<8);                                           \
    c2 += (*zIn++);                                                   \
    c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);   \
  }                                                                   \
}

/*
** Translate a single UTF-8 character.  Return the unicode value.
**
** During translation, assume that the byte that zTerm points
** is a 0x00.
**
** Write a pointer to the next unread byte back into *pzNext.







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







30623
30624
30625
30626
30627
30628
30629




















30630
30631
30632
30633
30634
30635
30636
    *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03));              \
    *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0));  \
    *zOut++ = (u8)(0x00DC + ((c>>8)&0x03));                         \
    *zOut++ = (u8)(c&0x00FF);                                       \
  }                                                                 \
}





















/*
** Translate a single UTF-8 character.  Return the unicode value.
**
** During translation, assume that the byte that zTerm points
** is a 0x00.
**
** Write a pointer to the next unread byte back into *pzNext.
30250
30251
30252
30253
30254
30255
30256

30257

30258
30259
30260
30261
30262
30263
30264
30265
30266
  assert( pMem->flags&MEM_Str );
  assert( pMem->enc!=desiredEnc );
  assert( pMem->enc!=0 );
  assert( pMem->n>=0 );

#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
  {

    char zBuf[100];

    sqlite3VdbeMemPrettyPrint(pMem, zBuf);
    fprintf(stderr, "INPUT:  %s\n", zBuf);
  }
#endif

  /* If the translation is between UTF-16 little and big endian, then 
  ** all that is required is to swap the byte order. This case is handled
  ** differently from the others.
  */







>
|
>
|
|







30713
30714
30715
30716
30717
30718
30719
30720
30721
30722
30723
30724
30725
30726
30727
30728
30729
30730
30731
  assert( pMem->flags&MEM_Str );
  assert( pMem->enc!=desiredEnc );
  assert( pMem->enc!=0 );
  assert( pMem->n>=0 );

#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
  {
    StrAccum acc;
    char zBuf[1000];
    sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);  
    sqlite3VdbeMemPrettyPrint(pMem, &acc);
    fprintf(stderr, "INPUT:  %s\n", sqlite3StrAccumFinish(&acc));
  }
#endif

  /* If the translation is between UTF-16 little and big endian, then 
  ** all that is required is to swap the byte order. This case is handled
  ** differently from the others.
  */
30334
30335
30336
30337
30338
30339
30340
30341















30342
30343
30344
30345
30346

30347














30348
30349
30350
30351
30352
30353
30354
30355
30356
30357
30358
30359
30360
30361
30362
30363
30364
30365
30366

30367

30368
30369
30370
30371
30372
30373
30374
30375
30376
    pMem->n = (int)(z - zOut);
    *z++ = 0;
  }else{
    assert( desiredEnc==SQLITE_UTF8 );
    if( pMem->enc==SQLITE_UTF16LE ){
      /* UTF-16 Little-endian -> UTF-8 */
      while( zIn<zTerm ){
        READ_UTF16LE(zIn, zIn<zTerm, c); 















        WRITE_UTF8(z, c);
      }
    }else{
      /* UTF-16 Big-endian -> UTF-8 */
      while( zIn<zTerm ){

        READ_UTF16BE(zIn, zIn<zTerm, c); 














        WRITE_UTF8(z, c);
      }
    }
    pMem->n = (int)(z - zOut);
  }
  *z = 0;
  assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );

  c = pMem->flags;
  sqlite3VdbeMemRelease(pMem);
  pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
  pMem->enc = desiredEnc;
  pMem->z = (char*)zOut;
  pMem->zMalloc = pMem->z;
  pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z);

translate_out:
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
  {

    char zBuf[100];

    sqlite3VdbeMemPrettyPrint(pMem, zBuf);
    fprintf(stderr, "OUTPUT: %s\n", zBuf);
  }
#endif
  return SQLITE_OK;
}
#endif /* SQLITE_OMIT_UTF16 */

#ifndef SQLITE_OMIT_UTF16







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





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



















>
|
>
|
|







30799
30800
30801
30802
30803
30804
30805
30806
30807
30808
30809
30810
30811
30812
30813
30814
30815
30816
30817
30818
30819
30820
30821
30822
30823
30824
30825
30826
30827
30828
30829
30830
30831
30832
30833
30834
30835
30836
30837
30838
30839
30840
30841
30842
30843
30844
30845
30846
30847
30848
30849
30850
30851
30852
30853
30854
30855
30856
30857
30858
30859
30860
30861
30862
30863
30864
30865
30866
30867
30868
30869
30870
30871
30872
30873
    pMem->n = (int)(z - zOut);
    *z++ = 0;
  }else{
    assert( desiredEnc==SQLITE_UTF8 );
    if( pMem->enc==SQLITE_UTF16LE ){
      /* UTF-16 Little-endian -> UTF-8 */
      while( zIn<zTerm ){
        c = *(zIn++);
        c += (*(zIn++))<<8;
        if( c>=0xd800 && c<0xe000 ){
          if( c>=0xdc00 || zIn>=zTerm ){
            c = 0xfffd;
          }else{
            int c2 = *(zIn++);
            c2 += (*(zIn++))<<8;
            if( c2<0xdc00 || c2>=0xe000 ){
              zIn -= 2;
              c = 0xfffd;
            }else{
              c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
            }
          }
        }
        WRITE_UTF8(z, c);
      }
    }else{
      /* UTF-16 Big-endian -> UTF-8 */
      while( zIn<zTerm ){
        c = (*(zIn++))<<8;
        c += *(zIn++);
        if( c>=0xd800 && c<0xe000 ){
          if( c>=0xdc00 || zIn>=zTerm ){
            c = 0xfffd;
          }else{
            int c2 = (*(zIn++))<<8;
            c2 += *(zIn++);
            if( c2<0xdc00 || c2>=0xe000 ){
              zIn -= 2;
              c = 0xfffd;
            }else{
              c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
            }
          }
        }
        WRITE_UTF8(z, c);
      }
    }
    pMem->n = (int)(z - zOut);
  }
  *z = 0;
  assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );

  c = pMem->flags;
  sqlite3VdbeMemRelease(pMem);
  pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
  pMem->enc = desiredEnc;
  pMem->z = (char*)zOut;
  pMem->zMalloc = pMem->z;
  pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z);

translate_out:
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
  {
    StrAccum acc;
    char zBuf[1000];
    sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);  
    sqlite3VdbeMemPrettyPrint(pMem, &acc);
    fprintf(stderr, "OUTPUT: %s\n", sqlite3StrAccumFinish(&acc));
  }
#endif
  return SQLITE_OK;
}
#endif /* SQLITE_OMIT_UTF16 */

#ifndef SQLITE_OMIT_UTF16
30497
30498
30499
30500
30501
30502
30503
30504
30505
30506
30507
30508
30509
30510
30511

30512
30513
30514
30515

30516
30517
30518
30519
30520
30521
30522
** in pZ.  nChar must be non-negative.
*/
SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
  int c;
  unsigned char const *z = zIn;
  int n = 0;
  
  if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
    while( n<nChar ){
      READ_UTF16BE(z, 1, c);
      n++;
    }
  }else{
    while( n<nChar ){
      READ_UTF16LE(z, 1, c);

      n++;
    }
  }
  return (int)(z-(unsigned char const *)zIn);

}

#if defined(SQLITE_TEST)
/*
** This routine is called from the TCL test function "translate_selftest".
** It checks that the primitives for serializing and deserializing
** characters in each encoding are inverses of each other.







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







30994
30995
30996
30997
30998
30999
31000
31001
31002
31003
31004




31005
31006
31007

31008
31009
31010
31011
31012
31013
31014
31015
31016
** in pZ.  nChar must be non-negative.
*/
SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
  int c;
  unsigned char const *z = zIn;
  int n = 0;
  
  if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
  while( n<nChar ){
    c = z[0];
    z += 2;




    if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
    n++;
  }

  return (int)(z-(unsigned char const *)zIn) 
              - (SQLITE_UTF16NATIVE==SQLITE_UTF16LE);
}

#if defined(SQLITE_TEST)
/*
** This routine is called from the TCL test function "translate_selftest".
** It checks that the primitives for serializing and deserializing
** characters in each encoding are inverses of each other.
30538
30539
30540
30541
30542
30543
30544
30545
30546
30547
30548
30549
30550
30551
30552
30553
30554
30555
30556
30557
30558
30559
30560
30561
30562
30563
30564
30565
30566
30567
30568
30569
30570
30571
30572
30573
30574
30575
    c = sqlite3Utf8Read((const u8**)&z);
    t = i;
    if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
    if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
    assert( c==t );
    assert( (z-zBuf)==n );
  }
  for(i=0; i<0x00110000; i++){
    if( i>=0xD800 && i<0xE000 ) continue;
    z = zBuf;
    WRITE_UTF16LE(z, i);
    n = (int)(z-zBuf);
    assert( n>0 && n<=4 );
    z[0] = 0;
    z = zBuf;
    READ_UTF16LE(z, 1, c);
    assert( c==i );
    assert( (z-zBuf)==n );
  }
  for(i=0; i<0x00110000; i++){
    if( i>=0xD800 && i<0xE000 ) continue;
    z = zBuf;
    WRITE_UTF16BE(z, i);
    n = (int)(z-zBuf);
    assert( n>0 && n<=4 );
    z[0] = 0;
    z = zBuf;
    READ_UTF16BE(z, 1, c);
    assert( c==i );
    assert( (z-zBuf)==n );
  }
}
#endif /* SQLITE_TEST */
#endif /* SQLITE_OMIT_UTF16 */

/************** End of utf.c *************************************************/
/************** Begin file util.c ********************************************/
/*







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







31032
31033
31034
31035
31036
31037
31038
























31039
31040
31041
31042
31043
31044
31045
    c = sqlite3Utf8Read((const u8**)&z);
    t = i;
    if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
    if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
    assert( c==t );
    assert( (z-zBuf)==n );
  }
























}
#endif /* SQLITE_TEST */
#endif /* SQLITE_OMIT_UTF16 */

/************** End of utf.c *************************************************/
/************** Begin file util.c ********************************************/
/*
30587
30588
30589
30590
30591
30592
30593

30594

30595
30596
30597
30598
30599
30600
30601
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
*/
/* #include "sqliteInt.h" */
/* #include <stdarg.h> */

#include <math.h>


/*
** Routine needed to support the testcase() macro.
*/
#ifdef SQLITE_COVERAGE_TEST
SQLITE_PRIVATE void sqlite3Coverage(int x){
  static unsigned dummy = 0;







>

>







31057
31058
31059
31060
31061
31062
31063
31064
31065
31066
31067
31068
31069
31070
31071
31072
31073
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
*/
/* #include "sqliteInt.h" */
/* #include <stdarg.h> */
#ifndef SQLITE_OMIT_FLOATING_POINT
#include <math.h>
#endif

/*
** Routine needed to support the testcase() macro.
*/
#ifdef SQLITE_COVERAGE_TEST
SQLITE_PRIVATE void sqlite3Coverage(int x){
  static unsigned dummy = 0;
30884
30885
30886
30887
30888
30889
30890













30891
30892
30893
30894
30895
30896
30897
    return 1;
  }
  a = (unsigned char *)zLeft;
  b = (unsigned char *)zRight;
  while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
  return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
}














/*
** Compute 10 to the E-th power.  Examples:  E==1 results in 10.
** E==2 results in 100.  E==50 results in 1.0e50.
**
** This routine only works for values of E between 1 and 341.
*/







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







31356
31357
31358
31359
31360
31361
31362
31363
31364
31365
31366
31367
31368
31369
31370
31371
31372
31373
31374
31375
31376
31377
31378
31379
31380
31381
31382
    return 1;
  }
  a = (unsigned char *)zLeft;
  b = (unsigned char *)zRight;
  while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
  return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
}

/*
** Compute an 8-bit hash on a string that is insensitive to case differences
*/
SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){
  u8 h = 0;
  if( z==0 ) return 0;
  while( z[0] ){
    h += UpperToLower[(unsigned char)z[0]];
    z++;
  }
  return h;
}

/*
** Compute 10 to the E-th power.  Examples:  E==1 results in 10.
** E==2 results in 100.  E==50 results in 1.0e50.
**
** This routine only works for values of E between 1 and 341.
*/
30959
30960
30961
30962
30963
30964
30965
30966
30967
30968
30969
30970
30971
30972
30973
30974
30975
30976
30977
30978
30979

30980
30981
30982

30983
30984
30985

30986
30987
30988
30989
30990
30991
30992
*/
#if defined(_MSC_VER)
#pragma warning(disable : 4756)
#endif
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
#ifndef SQLITE_OMIT_FLOATING_POINT
  int incr;
  const char *zEnd = z + length;
  /* sign * significand * (10 ^ (esign * exponent)) */
  int sign = 1;    /* sign of significand */
  i64 s = 0;       /* significand */
  int d = 0;       /* adjust exponent for shifting decimal point */
  int esign = 1;   /* sign of exponent */
  int e = 0;       /* exponent */
  int eValid = 1;  /* True exponent is either not used or is well-formed */
  double result;
  int nDigit = 0;  /* Number of digits processed */
  int eType = 1;   /* 1: pure integer,  2+: fractional  -1 or less: bad UTF16 */

  assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
  *pResult = 0.0;   /* Default return value, in case of an error */


  if( enc==SQLITE_UTF8 ){
    incr = 1;

  }else{
    int i;
    incr = 2;

    assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
    testcase( enc==SQLITE_UTF16LE );
    testcase( enc==SQLITE_UTF16BE );
    for(i=3-enc; i<length && z[i]==0; i+=2){}
    if( i<length ) eType = -100;
    zEnd = &z[i^1];
    z += (enc&1);







|













>



>



>







31444
31445
31446
31447
31448
31449
31450
31451
31452
31453
31454
31455
31456
31457
31458
31459
31460
31461
31462
31463
31464
31465
31466
31467
31468
31469
31470
31471
31472
31473
31474
31475
31476
31477
31478
31479
31480
*/
#if defined(_MSC_VER)
#pragma warning(disable : 4756)
#endif
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
#ifndef SQLITE_OMIT_FLOATING_POINT
  int incr;
  const char *zEnd;
  /* sign * significand * (10 ^ (esign * exponent)) */
  int sign = 1;    /* sign of significand */
  i64 s = 0;       /* significand */
  int d = 0;       /* adjust exponent for shifting decimal point */
  int esign = 1;   /* sign of exponent */
  int e = 0;       /* exponent */
  int eValid = 1;  /* True exponent is either not used or is well-formed */
  double result;
  int nDigit = 0;  /* Number of digits processed */
  int eType = 1;   /* 1: pure integer,  2+: fractional  -1 or less: bad UTF16 */

  assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
  *pResult = 0.0;   /* Default return value, in case of an error */
  if( length==0 ) return 0;

  if( enc==SQLITE_UTF8 ){
    incr = 1;
    zEnd = z + length;
  }else{
    int i;
    incr = 2;
    length &= ~1;
    assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
    testcase( enc==SQLITE_UTF16LE );
    testcase( enc==SQLITE_UTF16BE );
    for(i=3-enc; i<length && z[i]==0; i+=2){}
    if( i<length ) eType = -100;
    zEnd = &z[i^1];
    z += (enc&1);
31821
31822
31823
31824
31825
31826
31827
31828
31829
31830
31831
31832
31833
31834
31835
31836
31837
31838
31839
31840
31841
31842
31843
31844
31845
31846
31847
31848
31849
31850
31851
31852
31853
31854
31855
31856
#endif
#ifdef SQLITE_EBCDIC
  h += 9*(1&~(h>>4));
#endif
  return (u8)(h & 0xf);
}

#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/*
** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
** value.  Return a pointer to its binary value.  Space to hold the
** binary value has been obtained from malloc and must be freed by
** the calling routine.
*/
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
  char *zBlob;
  int i;

  zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1);
  n--;
  if( zBlob ){
    for(i=0; i<n; i+=2){
      zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]);
    }
    zBlob[i/2] = 0;
  }
  return zBlob;
}
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */

/*
** Log an error that is an API call on a connection pointer that should
** not have been used.  The "type" of connection pointer is given as the
** argument.  The zType is a word like "NULL" or "closed" or "invalid".
*/
static void logBadConnection(const char *zType){







|




















|







32309
32310
32311
32312
32313
32314
32315
32316
32317
32318
32319
32320
32321
32322
32323
32324
32325
32326
32327
32328
32329
32330
32331
32332
32333
32334
32335
32336
32337
32338
32339
32340
32341
32342
32343
32344
#endif
#ifdef SQLITE_EBCDIC
  h += 9*(1&~(h>>4));
#endif
  return (u8)(h & 0xf);
}

#if !defined(SQLITE_OMIT_BLOB_LITERAL)
/*
** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
** value.  Return a pointer to its binary value.  Space to hold the
** binary value has been obtained from malloc and must be freed by
** the calling routine.
*/
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
  char *zBlob;
  int i;

  zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1);
  n--;
  if( zBlob ){
    for(i=0; i<n; i+=2){
      zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]);
    }
    zBlob[i/2] = 0;
  }
  return zBlob;
}
#endif /* !SQLITE_OMIT_BLOB_LITERAL */

/*
** Log an error that is an API call on a connection pointer that should
** not have been used.  The "type" of connection pointer is given as the
** argument.  The zType is a word like "NULL" or "closed" or "invalid".
*/
static void logBadConnection(const char *zType){
32516
32517
32518
32519
32520
32521
32522

32523
32524
32525
32526
32527
32528
32529
32530
32531
32532
32533
32534
32535
32536
32537
32538
32539
32540
32541

32542
32543
32544
32545
32546
32547
32548
32549
32550
32551
32552
32553
32554
32555

32556
32557
32558
32559
32560
32561
32562
32563
32564
32565
32566
32567
32568
32569
32570
32571
32572
32573
32574
32575
32576
32577
32578
32579
32580
32581
32582
32583
32584
32585
32586
32587
32588
32589
32590
32591
32592
32593
32594
32595
32596
32597
32598
32599
32600
32601
32602
32603
32604
32605
32606
32607
32608
32609

32610
32611
32612

32613
32614
32615
32616
32617
32618
32619
32620
32621
32622
32623
32624
32625
32626
32627

32628
32629
32630

32631
32632
32633
32634
32635
32636
32637
32638
32639
32640
32641
32642
32643
32644
32645
32646
32647


32648
32649
32650
32651
32652
32653


32654
32655
32656
32657
32658
32659
32660
32661
32662
32663
32664

32665
32666
32667
32668
32669
32670
32671
32672
32673
32674
    /*  19 */ "Not"              OpHelp("r[P2]= !r[P1]"),
    /*  20 */ "IfNot"            OpHelp(""),
    /*  21 */ "IfNullRow"        OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
    /*  22 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
    /*  23 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
    /*  24 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
    /*  25 */ "SeekGT"           OpHelp("key=r[P3@P4]"),

    /*  26 */ "IfNoHope"         OpHelp("key=r[P3@P4]"),
    /*  27 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
    /*  28 */ "NotFound"         OpHelp("key=r[P3@P4]"),
    /*  29 */ "Found"            OpHelp("key=r[P3@P4]"),
    /*  30 */ "SeekRowid"        OpHelp("intkey=r[P3]"),
    /*  31 */ "NotExists"        OpHelp("intkey=r[P3]"),
    /*  32 */ "Last"             OpHelp(""),
    /*  33 */ "IfSmaller"        OpHelp(""),
    /*  34 */ "SorterSort"       OpHelp(""),
    /*  35 */ "Sort"             OpHelp(""),
    /*  36 */ "Rewind"           OpHelp(""),
    /*  37 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
    /*  38 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
    /*  39 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
    /*  40 */ "IdxGE"            OpHelp("key=r[P3@P4]"),
    /*  41 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),
    /*  42 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
    /*  43 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
    /*  44 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),

    /*  45 */ "Program"          OpHelp(""),
    /*  46 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
    /*  47 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
    /*  48 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
    /*  49 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
    /*  50 */ "IsNull"           OpHelp("if r[P1]==NULL goto P2"),
    /*  51 */ "NotNull"          OpHelp("if r[P1]!=NULL goto P2"),
    /*  52 */ "Ne"               OpHelp("IF r[P3]!=r[P1]"),
    /*  53 */ "Eq"               OpHelp("IF r[P3]==r[P1]"),
    /*  54 */ "Gt"               OpHelp("IF r[P3]>r[P1]"),
    /*  55 */ "Le"               OpHelp("IF r[P3]<=r[P1]"),
    /*  56 */ "Lt"               OpHelp("IF r[P3]<r[P1]"),
    /*  57 */ "Ge"               OpHelp("IF r[P3]>=r[P1]"),
    /*  58 */ "ElseNotEq"        OpHelp(""),

    /*  59 */ "IncrVacuum"       OpHelp(""),
    /*  60 */ "VNext"            OpHelp(""),
    /*  61 */ "Init"             OpHelp("Start at P2"),
    /*  62 */ "PureFunc"         OpHelp("r[P3]=func(r[P2@P5])"),
    /*  63 */ "Function"         OpHelp("r[P3]=func(r[P2@P5])"),
    /*  64 */ "Return"           OpHelp(""),
    /*  65 */ "EndCoroutine"     OpHelp(""),
    /*  66 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
    /*  67 */ "Halt"             OpHelp(""),
    /*  68 */ "Integer"          OpHelp("r[P2]=P1"),
    /*  69 */ "Int64"            OpHelp("r[P2]=P4"),
    /*  70 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
    /*  71 */ "Null"             OpHelp("r[P2..P3]=NULL"),
    /*  72 */ "SoftNull"         OpHelp("r[P1]=NULL"),
    /*  73 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
    /*  74 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
    /*  75 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
    /*  76 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
    /*  77 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
    /*  78 */ "IntCopy"          OpHelp("r[P2]=r[P1]"),
    /*  79 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
    /*  80 */ "CollSeq"          OpHelp(""),
    /*  81 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
    /*  82 */ "RealAffinity"     OpHelp(""),
    /*  83 */ "Cast"             OpHelp("affinity(r[P1])"),
    /*  84 */ "Permutation"      OpHelp(""),
    /*  85 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
    /*  86 */ "IsTrue"           OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
    /*  87 */ "Offset"           OpHelp("r[P3] = sqlite_offset(P1)"),
    /*  88 */ "Column"           OpHelp("r[P3]=PX"),
    /*  89 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
    /*  90 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
    /*  91 */ "Count"            OpHelp("r[P2]=count()"),
    /*  92 */ "ReadCookie"       OpHelp(""),
    /*  93 */ "SetCookie"        OpHelp(""),
    /*  94 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
    /*  95 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
    /*  96 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),
    /*  97 */ "OpenDup"          OpHelp(""),
    /*  98 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
    /*  99 */ "OpenEphemeral"    OpHelp("nColumn=P2"),
    /* 100 */ "SorterOpen"       OpHelp(""),
    /* 101 */ "BitAnd"           OpHelp("r[P3]=r[P1]&r[P2]"),
    /* 102 */ "BitOr"            OpHelp("r[P3]=r[P1]|r[P2]"),
    /* 103 */ "ShiftLeft"        OpHelp("r[P3]=r[P2]<<r[P1]"),
    /* 104 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
    /* 105 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
    /* 106 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
    /* 107 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
    /* 108 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
    /* 109 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
    /* 110 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
    /* 111 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
    /* 112 */ "BitNot"           OpHelp("r[P2]= ~r[P1]"),

    /* 113 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),
    /* 114 */ "Close"            OpHelp(""),
    /* 115 */ "String8"          OpHelp("r[P2]='P4'"),

    /* 116 */ "ColumnsUsed"      OpHelp(""),
    /* 117 */ "SeekHit"          OpHelp("seekHit=P2"),
    /* 118 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
    /* 119 */ "NewRowid"         OpHelp("r[P2]=rowid"),
    /* 120 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
    /* 121 */ "Delete"           OpHelp(""),
    /* 122 */ "ResetCount"       OpHelp(""),
    /* 123 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
    /* 124 */ "SorterData"       OpHelp("r[P2]=data"),
    /* 125 */ "RowData"          OpHelp("r[P2]=data"),
    /* 126 */ "Rowid"            OpHelp("r[P2]=rowid"),
    /* 127 */ "NullRow"          OpHelp(""),
    /* 128 */ "SeekEnd"          OpHelp(""),
    /* 129 */ "SorterInsert"     OpHelp("key=r[P2]"),
    /* 130 */ "IdxInsert"        OpHelp("key=r[P2]"),

    /* 131 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
    /* 132 */ "DeferredSeek"     OpHelp("Move P3 to P1.rowid if needed"),
    /* 133 */ "IdxRowid"         OpHelp("r[P2]=rowid"),

    /* 134 */ "Destroy"          OpHelp(""),
    /* 135 */ "Clear"            OpHelp(""),
    /* 136 */ "ResetSorter"      OpHelp(""),
    /* 137 */ "CreateBtree"      OpHelp("r[P2]=root iDb=P1 flags=P3"),
    /* 138 */ "SqlExec"          OpHelp(""),
    /* 139 */ "ParseSchema"      OpHelp(""),
    /* 140 */ "LoadAnalysis"     OpHelp(""),
    /* 141 */ "DropTable"        OpHelp(""),
    /* 142 */ "DropIndex"        OpHelp(""),
    /* 143 */ "DropTrigger"      OpHelp(""),
    /* 144 */ "IntegrityCk"      OpHelp(""),
    /* 145 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
    /* 146 */ "Param"            OpHelp(""),
    /* 147 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
    /* 148 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
    /* 149 */ "OffsetLimit"      OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
    /* 150 */ "Real"             OpHelp("r[P2]=P4"),


    /* 151 */ "AggInverse"       OpHelp("accum=r[P3] inverse(r[P2@P5])"),
    /* 152 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
    /* 153 */ "AggStep1"         OpHelp("accum=r[P3] step(r[P2@P5])"),
    /* 154 */ "AggValue"         OpHelp("r[P3]=value N=P2"),
    /* 155 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
    /* 156 */ "Expire"           OpHelp(""),


    /* 157 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
    /* 158 */ "VBegin"           OpHelp(""),
    /* 159 */ "VCreate"          OpHelp(""),
    /* 160 */ "VDestroy"         OpHelp(""),
    /* 161 */ "VOpen"            OpHelp(""),
    /* 162 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
    /* 163 */ "VRename"          OpHelp(""),
    /* 164 */ "Pagecount"        OpHelp(""),
    /* 165 */ "MaxPgcnt"         OpHelp(""),
    /* 166 */ "Trace"            OpHelp(""),
    /* 167 */ "CursorHint"       OpHelp(""),

    /* 168 */ "Noop"             OpHelp(""),
    /* 169 */ "Explain"          OpHelp(""),
    /* 170 */ "Abortable"        OpHelp(""),
  };
  return azName[i];
}
#endif

/************** End of opcodes.c *********************************************/
/************** Begin file os_unix.c *****************************************/







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


>
|
|
|
|
<









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










|

>
|
<

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

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

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







33004
33005
33006
33007
33008
33009
33010
33011
33012
33013
33014
33015
33016
33017
33018
33019
33020
33021
33022
33023
33024
33025
33026
33027

33028
33029
33030
33031
33032
33033
33034

33035
33036
33037
33038
33039
33040
33041
33042
33043
33044
33045
33046
33047
33048
33049
33050
33051
33052
33053
33054
33055
33056
33057
33058
33059
33060
33061
33062
33063
33064
33065
33066
33067
33068
33069
33070
33071
33072
33073
33074
33075
33076
33077
33078
33079
33080
33081
33082
33083
33084
33085

33086
33087
33088
33089
33090
33091
33092
33093
33094
33095
33096
33097
33098
33099

33100
33101
33102
33103
33104
33105
33106
33107
33108
33109
33110
33111
33112
33113
33114

33115
33116
33117
33118
33119
33120
33121
33122
33123
33124
33125
33126
33127
33128
33129
33130
33131
33132
33133
33134


33135
33136
33137
33138
33139
33140
33141
33142
33143
33144
33145
33146
33147
33148
33149
33150
33151
33152
33153
33154
33155
33156
33157
33158
33159
33160
33161
33162
33163
33164
33165
33166
33167
    /*  19 */ "Not"              OpHelp("r[P2]= !r[P1]"),
    /*  20 */ "IfNot"            OpHelp(""),
    /*  21 */ "IfNullRow"        OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
    /*  22 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
    /*  23 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
    /*  24 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
    /*  25 */ "SeekGT"           OpHelp("key=r[P3@P4]"),
    /*  26 */ "IfNotOpen"        OpHelp("if( !csr[P1] ) goto P2"),
    /*  27 */ "IfNoHope"         OpHelp("key=r[P3@P4]"),
    /*  28 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
    /*  29 */ "NotFound"         OpHelp("key=r[P3@P4]"),
    /*  30 */ "Found"            OpHelp("key=r[P3@P4]"),
    /*  31 */ "SeekRowid"        OpHelp("intkey=r[P3]"),
    /*  32 */ "NotExists"        OpHelp("intkey=r[P3]"),
    /*  33 */ "Last"             OpHelp(""),
    /*  34 */ "IfSmaller"        OpHelp(""),
    /*  35 */ "SorterSort"       OpHelp(""),
    /*  36 */ "Sort"             OpHelp(""),
    /*  37 */ "Rewind"           OpHelp(""),
    /*  38 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
    /*  39 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
    /*  40 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
    /*  41 */ "IdxGE"            OpHelp("key=r[P3@P4]"),
    /*  42 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),

    /*  43 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
    /*  44 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),
    /*  45 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
    /*  46 */ "Program"          OpHelp(""),
    /*  47 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
    /*  48 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
    /*  49 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),

    /*  50 */ "IsNull"           OpHelp("if r[P1]==NULL goto P2"),
    /*  51 */ "NotNull"          OpHelp("if r[P1]!=NULL goto P2"),
    /*  52 */ "Ne"               OpHelp("IF r[P3]!=r[P1]"),
    /*  53 */ "Eq"               OpHelp("IF r[P3]==r[P1]"),
    /*  54 */ "Gt"               OpHelp("IF r[P3]>r[P1]"),
    /*  55 */ "Le"               OpHelp("IF r[P3]<=r[P1]"),
    /*  56 */ "Lt"               OpHelp("IF r[P3]<r[P1]"),
    /*  57 */ "Ge"               OpHelp("IF r[P3]>=r[P1]"),
    /*  58 */ "ElseNotEq"        OpHelp(""),
    /*  59 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
    /*  60 */ "IncrVacuum"       OpHelp(""),
    /*  61 */ "VNext"            OpHelp(""),
    /*  62 */ "Init"             OpHelp("Start at P2"),
    /*  63 */ "PureFunc"         OpHelp("r[P3]=func(r[P2@NP])"),
    /*  64 */ "Function"         OpHelp("r[P3]=func(r[P2@NP])"),
    /*  65 */ "Return"           OpHelp(""),
    /*  66 */ "EndCoroutine"     OpHelp(""),
    /*  67 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
    /*  68 */ "Halt"             OpHelp(""),
    /*  69 */ "Integer"          OpHelp("r[P2]=P1"),
    /*  70 */ "Int64"            OpHelp("r[P2]=P4"),
    /*  71 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
    /*  72 */ "Null"             OpHelp("r[P2..P3]=NULL"),
    /*  73 */ "SoftNull"         OpHelp("r[P1]=NULL"),
    /*  74 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
    /*  75 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
    /*  76 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
    /*  77 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
    /*  78 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
    /*  79 */ "IntCopy"          OpHelp("r[P2]=r[P1]"),
    /*  80 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
    /*  81 */ "CollSeq"          OpHelp(""),
    /*  82 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
    /*  83 */ "RealAffinity"     OpHelp(""),
    /*  84 */ "Cast"             OpHelp("affinity(r[P1])"),
    /*  85 */ "Permutation"      OpHelp(""),
    /*  86 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
    /*  87 */ "IsTrue"           OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
    /*  88 */ "Offset"           OpHelp("r[P3] = sqlite_offset(P1)"),
    /*  89 */ "Column"           OpHelp("r[P3]=PX"),
    /*  90 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
    /*  91 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
    /*  92 */ "Count"            OpHelp("r[P2]=count()"),
    /*  93 */ "ReadCookie"       OpHelp(""),
    /*  94 */ "SetCookie"        OpHelp(""),
    /*  95 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
    /*  96 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
    /*  97 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),
    /*  98 */ "OpenDup"          OpHelp(""),
    /*  99 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
    /* 100 */ "OpenEphemeral"    OpHelp("nColumn=P2"),

    /* 101 */ "BitAnd"           OpHelp("r[P3]=r[P1]&r[P2]"),
    /* 102 */ "BitOr"            OpHelp("r[P3]=r[P1]|r[P2]"),
    /* 103 */ "ShiftLeft"        OpHelp("r[P3]=r[P2]<<r[P1]"),
    /* 104 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
    /* 105 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
    /* 106 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
    /* 107 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
    /* 108 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
    /* 109 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
    /* 110 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
    /* 111 */ "SorterOpen"       OpHelp(""),
    /* 112 */ "BitNot"           OpHelp("r[P2]= ~r[P1]"),
    /* 113 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
    /* 114 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),

    /* 115 */ "String8"          OpHelp("r[P2]='P4'"),
    /* 116 */ "Close"            OpHelp(""),
    /* 117 */ "ColumnsUsed"      OpHelp(""),
    /* 118 */ "SeekHit"          OpHelp("seekHit=P2"),
    /* 119 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
    /* 120 */ "NewRowid"         OpHelp("r[P2]=rowid"),
    /* 121 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
    /* 122 */ "Delete"           OpHelp(""),
    /* 123 */ "ResetCount"       OpHelp(""),
    /* 124 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
    /* 125 */ "SorterData"       OpHelp("r[P2]=data"),
    /* 126 */ "RowData"          OpHelp("r[P2]=data"),
    /* 127 */ "Rowid"            OpHelp("r[P2]=rowid"),
    /* 128 */ "NullRow"          OpHelp(""),
    /* 129 */ "SeekEnd"          OpHelp(""),

    /* 130 */ "IdxInsert"        OpHelp("key=r[P2]"),
    /* 131 */ "SorterInsert"     OpHelp("key=r[P2]"),
    /* 132 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
    /* 133 */ "DeferredSeek"     OpHelp("Move P3 to P1.rowid if needed"),
    /* 134 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
    /* 135 */ "FinishSeek"       OpHelp(""),
    /* 136 */ "Destroy"          OpHelp(""),
    /* 137 */ "Clear"            OpHelp(""),
    /* 138 */ "ResetSorter"      OpHelp(""),
    /* 139 */ "CreateBtree"      OpHelp("r[P2]=root iDb=P1 flags=P3"),
    /* 140 */ "SqlExec"          OpHelp(""),
    /* 141 */ "ParseSchema"      OpHelp(""),
    /* 142 */ "LoadAnalysis"     OpHelp(""),
    /* 143 */ "DropTable"        OpHelp(""),
    /* 144 */ "DropIndex"        OpHelp(""),
    /* 145 */ "DropTrigger"      OpHelp(""),
    /* 146 */ "IntegrityCk"      OpHelp(""),
    /* 147 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
    /* 148 */ "Param"            OpHelp(""),
    /* 149 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),


    /* 150 */ "Real"             OpHelp("r[P2]=P4"),
    /* 151 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
    /* 152 */ "OffsetLimit"      OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
    /* 153 */ "AggInverse"       OpHelp("accum=r[P3] inverse(r[P2@P5])"),
    /* 154 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
    /* 155 */ "AggStep1"         OpHelp("accum=r[P3] step(r[P2@P5])"),
    /* 156 */ "AggValue"         OpHelp("r[P3]=value N=P2"),
    /* 157 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
    /* 158 */ "Expire"           OpHelp(""),
    /* 159 */ "CursorLock"       OpHelp(""),
    /* 160 */ "CursorUnlock"     OpHelp(""),
    /* 161 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
    /* 162 */ "VBegin"           OpHelp(""),
    /* 163 */ "VCreate"          OpHelp(""),
    /* 164 */ "VDestroy"         OpHelp(""),
    /* 165 */ "VOpen"            OpHelp(""),
    /* 166 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
    /* 167 */ "VRename"          OpHelp(""),
    /* 168 */ "Pagecount"        OpHelp(""),
    /* 169 */ "MaxPgcnt"         OpHelp(""),
    /* 170 */ "Trace"            OpHelp(""),
    /* 171 */ "CursorHint"       OpHelp(""),
    /* 172 */ "ReleaseReg"       OpHelp("release r[P1@P2] mask P3"),
    /* 173 */ "Noop"             OpHelp(""),
    /* 174 */ "Explain"          OpHelp(""),
    /* 175 */ "Abortable"        OpHelp(""),
  };
  return azName[i];
}
#endif

/************** End of opcodes.c *********************************************/
/************** Begin file os_unix.c *****************************************/
33557
33558
33559
33560
33561
33562
33563
33564
33565
33566
33567
33568
33569
33570
33571
      break;
    }
    if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
    osClose(fd);
    sqlite3_log(SQLITE_WARNING, 
                "attempt to open \"%s\" as file descriptor %d", z, fd);
    fd = -1;
    if( osOpen("/dev/null", f, m)<0 ) break;
  }
  if( fd>=0 ){
    if( m!=0 ){
      struct stat statbuf;
      if( osFstat(fd, &statbuf)==0 
       && statbuf.st_size==0
       && (statbuf.st_mode&0777)!=m 







|







34050
34051
34052
34053
34054
34055
34056
34057
34058
34059
34060
34061
34062
34063
34064
      break;
    }
    if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
    osClose(fd);
    sqlite3_log(SQLITE_WARNING, 
                "attempt to open \"%s\" as file descriptor %d", z, fd);
    fd = -1;
    if( osOpen("/dev/null", O_RDONLY, m)<0 ) break;
  }
  if( fd>=0 ){
    if( m!=0 ){
      struct stat statbuf;
      if( osFstat(fd, &statbuf)==0 
       && statbuf.st_size==0
       && (statbuf.st_mode&0777)!=m 
36863
36864
36865
36866
36867
36868
36869

36870

36871
36872
36873
36874
36875
36876
36877
    }
    case SQLITE_FCNTL_HAS_MOVED: {
      *(int*)pArg = fileHasMoved(pFile);
      return SQLITE_OK;
    }
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    case SQLITE_FCNTL_LOCK_TIMEOUT: {

      pFile->iBusyTimeout = *(int*)pArg;

      return SQLITE_OK;
    }
#endif
#if SQLITE_MAX_MMAP_SIZE>0
    case SQLITE_FCNTL_MMAP_SIZE: {
      i64 newLimit = *(i64*)pArg;
      int rc = SQLITE_OK;







>

>







37356
37357
37358
37359
37360
37361
37362
37363
37364
37365
37366
37367
37368
37369
37370
37371
37372
    }
    case SQLITE_FCNTL_HAS_MOVED: {
      *(int*)pArg = fileHasMoved(pFile);
      return SQLITE_OK;
    }
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    case SQLITE_FCNTL_LOCK_TIMEOUT: {
      int iOld = pFile->iBusyTimeout;
      pFile->iBusyTimeout = *(int*)pArg;
      *(int*)pArg = iOld;
      return SQLITE_OK;
    }
#endif
#if SQLITE_MAX_MMAP_SIZE>0
    case SQLITE_FCNTL_MMAP_SIZE: {
      i64 newLimit = *(i64*)pArg;
      int rc = SQLITE_OK;
37444
37445
37446
37447
37448
37449
37450
37451

37452
37453
37454

37455
37456
37457
37458
37459
37460
37461
        rc = SQLITE_NOMEM_BKPT;
        goto shm_open_err;
      }
    }

    if( pInode->bProcessLock==0 ){
      if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
        pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT,(sStat.st_mode&0777));

      }
      if( pShmNode->hShm<0 ){
        pShmNode->hShm = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777));

        if( pShmNode->hShm<0 ){
          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm);
          goto shm_open_err;
        }
        pShmNode->isReadonly = 1;
      }








|
>


|
>







37939
37940
37941
37942
37943
37944
37945
37946
37947
37948
37949
37950
37951
37952
37953
37954
37955
37956
37957
37958
        rc = SQLITE_NOMEM_BKPT;
        goto shm_open_err;
      }
    }

    if( pInode->bProcessLock==0 ){
      if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
        pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW,
                                     (sStat.st_mode&0777));
      }
      if( pShmNode->hShm<0 ){
        pShmNode->hShm = robust_open(zShm, O_RDONLY|O_NOFOLLOW,
                                     (sStat.st_mode&0777));
        if( pShmNode->hShm<0 ){
          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm);
          goto shm_open_err;
        }
        pShmNode->isReadonly = 1;
      }

37682
37683
37684
37685
37686
37687
37688


















37689
37690
37691
37692
37693
37694
37695
  assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
       || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
       || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
       || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
  assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
  assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
  assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );



















  mask = (1<<(ofst+n)) - (1<<ofst);
  assert( n>1 || mask==(1<<ofst) );
  sqlite3_mutex_enter(pShmNode->pShmMutex);
  if( flags & SQLITE_SHM_UNLOCK ){
    u16 allMask = 0; /* Mask of locks held by siblings */








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







38179
38180
38181
38182
38183
38184
38185
38186
38187
38188
38189
38190
38191
38192
38193
38194
38195
38196
38197
38198
38199
38200
38201
38202
38203
38204
38205
38206
38207
38208
38209
38210
  assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
       || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
       || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
       || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
  assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
  assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
  assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );

  /* Check that, if this to be a blocking lock, that locks have been
  ** obtained in the following order.
  **
  **   1. Checkpointer lock (ofst==1).
  **   2. Recover lock (ofst==2).
  **   3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
  **   4. Write lock (ofst==0).
  **
  ** In other words, if this is a blocking lock, none of the locks that
  ** occur later in the above list than the lock being obtained may be
  ** held.  */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  assert( pDbFd->iBusyTimeout==0 
       || (flags & SQLITE_SHM_UNLOCK) || ofst==0
       || ((p->exclMask|p->sharedMask)&~((1<<ofst)-2))==0
  );
#endif

  mask = (1<<(ofst+n)) - (1<<ofst);
  assert( n>1 || mask==(1<<ofst) );
  sqlite3_mutex_enter(pShmNode->pShmMutex);
  if( flags & SQLITE_SHM_UNLOCK ){
    u16 allMask = 0; /* Mask of locks held by siblings */

38797
38798
38799
38800
38801
38802
38803
38804
38805
38806
38807
38808
38809
38810
38811
  sqlite3_file *pFile,         /* The file descriptor to be filled in */
  int flags,                   /* Input flags to control the opening */
  int *pOutFlags               /* Output flags returned to SQLite core */
){
  unixFile *p = (unixFile *)pFile;
  int fd = -1;                   /* File descriptor returned by open() */
  int openFlags = 0;             /* Flags to pass to open() */
  int eType = flags&0xFFFFFF00;  /* Type of file to open */
  int noLock;                    /* True to omit locking primitives */
  int rc = SQLITE_OK;            /* Function Return Code */
  int ctrlFlags = 0;             /* UNIXFILE_* flags */

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isCreate     = (flags & SQLITE_OPEN_CREATE);







|







39312
39313
39314
39315
39316
39317
39318
39319
39320
39321
39322
39323
39324
39325
39326
  sqlite3_file *pFile,         /* The file descriptor to be filled in */
  int flags,                   /* Input flags to control the opening */
  int *pOutFlags               /* Output flags returned to SQLite core */
){
  unixFile *p = (unixFile *)pFile;
  int fd = -1;                   /* File descriptor returned by open() */
  int openFlags = 0;             /* Flags to pass to open() */
  int eType = flags&0x0FFF00;  /* Type of file to open */
  int noLock;                    /* True to omit locking primitives */
  int rc = SQLITE_OK;            /* Function Return Code */
  int ctrlFlags = 0;             /* UNIXFILE_* flags */

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isCreate     = (flags & SQLITE_OPEN_CREATE);
38907
38908
38909
38910
38911
38912
38913
38914
38915
38916
38917
38918
38919
38920
38921
  ** open(). These must be calculated even if open() is not called, as
  ** they may be stored as part of the file handle and used by the 
  ** 'conch file' locking functions later on.  */
  if( isReadonly )  openFlags |= O_RDONLY;
  if( isReadWrite ) openFlags |= O_RDWR;
  if( isCreate )    openFlags |= O_CREAT;
  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  openFlags |= (O_LARGEFILE|O_BINARY);

  if( fd<0 ){
    mode_t openMode;              /* Permissions to create file with */
    uid_t uid;                    /* Userid for the file */
    gid_t gid;                    /* Groupid for the file */
    rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
    if( rc!=SQLITE_OK ){







|







39422
39423
39424
39425
39426
39427
39428
39429
39430
39431
39432
39433
39434
39435
39436
  ** open(). These must be calculated even if open() is not called, as
  ** they may be stored as part of the file handle and used by the 
  ** 'conch file' locking functions later on.  */
  if( isReadonly )  openFlags |= O_RDONLY;
  if( isReadWrite ) openFlags |= O_RDWR;
  if( isCreate )    openFlags |= O_CREAT;
  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  openFlags |= (O_LARGEFILE|O_BINARY|O_NOFOLLOW);

  if( fd<0 ){
    mode_t openMode;              /* Permissions to create file with */
    uid_t uid;                    /* Userid for the file */
    gid_t gid;                    /* Groupid for the file */
    rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
    if( rc!=SQLITE_OK ){
39119
39120
39121
39122
39123
39124
39125
39126
39127
39128
39129
39130
39131
39132
39133
39134
39135
39136
39137
39138
39139
39140
39141
39142
39143
39144
39145
39146
39147
39148
39149
39150
39151
  int flags,              /* What do we want to learn about the zPath file? */
  int *pResOut            /* Write result boolean here */
){
  UNUSED_PARAMETER(NotUsed);
  SimulateIOError( return SQLITE_IOERR_ACCESS; );
  assert( pResOut!=0 );

  /* The spec says there are four possible values for flags.  But the
  ** SQLITE_ACCESS_READ flag is never used */
  assert( flags==SQLITE_ACCESS_EXISTS
       || flags==SQLITE_ACCESS_READWRITE
       || flags==SQLITE_ACCESS_SYMLINK );

  if( flags==SQLITE_ACCESS_EXISTS ){
    struct stat buf;
    *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0);
  }else if( flags==SQLITE_ACCESS_READWRITE ){
    *pResOut = osAccess(zPath, W_OK|R_OK)==0;
  }else{
#if !defined(HAVE_LSTAT)
    *pResOut = 0;
#else
    struct stat buf;
    *pResOut = (0==osLstat(zPath, &buf) && S_ISLNK(buf.st_mode));
#endif
    assert( flags==SQLITE_ACCESS_SYMLINK );
  }
  return SQLITE_OK;
}

/*
**
*/







|
|
|
<
<



|
|
<

<
|
<
<
<
<
<







39634
39635
39636
39637
39638
39639
39640
39641
39642
39643


39644
39645
39646
39647
39648

39649

39650





39651
39652
39653
39654
39655
39656
39657
  int flags,              /* What do we want to learn about the zPath file? */
  int *pResOut            /* Write result boolean here */
){
  UNUSED_PARAMETER(NotUsed);
  SimulateIOError( return SQLITE_IOERR_ACCESS; );
  assert( pResOut!=0 );

  /* The spec says there are three possible values for flags.  But only
  ** two of them are actually used */
  assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE );



  if( flags==SQLITE_ACCESS_EXISTS ){
    struct stat buf;
    *pResOut = 0==osStat(zPath, &buf) &&
                (!S_ISREG(buf.st_mode) || buf.st_size>0);

  }else{

    *pResOut = osAccess(zPath, W_OK|R_OK)==0;





  }
  return SQLITE_OK;
}

/*
**
*/
39189
39190
39191
39192
39193
39194
39195
39196
39197
39198
39199
39200
39201
39202
39203
  char *zOut                    /* Output buffer */
){
#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
  return mkFullPathname(zPath, zOut, nOut);
#else
  int rc = SQLITE_OK;
  int nByte;
  int nLink = 1;                /* Number of symbolic links followed so far */
  const char *zIn = zPath;      /* Input path for each iteration of loop */
  char *zDel = 0;

  assert( pVfs->mxPathname==MAX_PATHNAME );
  UNUSED_PARAMETER(pVfs);

  /* It's odd to simulate an io-error here, but really this is just







|







39695
39696
39697
39698
39699
39700
39701
39702
39703
39704
39705
39706
39707
39708
39709
  char *zOut                    /* Output buffer */
){
#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
  return mkFullPathname(zPath, zOut, nOut);
#else
  int rc = SQLITE_OK;
  int nByte;
  int nLink = 0;                /* Number of symbolic links followed so far */
  const char *zIn = zPath;      /* Input path for each iteration of loop */
  char *zDel = 0;

  assert( pVfs->mxPathname==MAX_PATHNAME );
  UNUSED_PARAMETER(pVfs);

  /* It's odd to simulate an io-error here, but really this is just
39218
39219
39220
39221
39222
39223
39224

39225
39226
39227
39228
39229
39230
39231
39232
39233
39234
39235
        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
      }
    }else{
      bLink = S_ISLNK(buf.st_mode);
    }

    if( bLink ){

      if( zDel==0 ){
        zDel = sqlite3_malloc(nOut);
        if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
      }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
        rc = SQLITE_CANTOPEN_BKPT;
      }

      if( rc==SQLITE_OK ){
        nByte = osReadlink(zIn, zDel, nOut-1);
        if( nByte<0 ){
          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);







>



|







39724
39725
39726
39727
39728
39729
39730
39731
39732
39733
39734
39735
39736
39737
39738
39739
39740
39741
39742
        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
      }
    }else{
      bLink = S_ISLNK(buf.st_mode);
    }

    if( bLink ){
      nLink++;
      if( zDel==0 ){
        zDel = sqlite3_malloc(nOut);
        if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
      }else if( nLink>=SQLITE_MAX_SYMLINKS ){
        rc = SQLITE_CANTOPEN_BKPT;
      }

      if( rc==SQLITE_OK ){
        nByte = osReadlink(zIn, zDel, nOut-1);
        if( nByte<0 ){
          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
39257
39258
39259
39260
39261
39262
39263

39264
39265
39266
39267
39268
39269
39270
      rc = mkFullPathname(zIn, zOut, nOut);
    }
    if( bLink==0 ) break;
    zIn = zOut;
  }while( rc==SQLITE_OK );

  sqlite3_free(zDel);

  return rc;
#endif   /* HAVE_READLINK && HAVE_LSTAT */
}


#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*







>







39764
39765
39766
39767
39768
39769
39770
39771
39772
39773
39774
39775
39776
39777
39778
      rc = mkFullPathname(zIn, zOut, nOut);
    }
    if( bLink==0 ) break;
    zIn = zOut;
  }while( rc==SQLITE_OK );

  sqlite3_free(zDel);
  if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK;
  return rc;
#endif   /* HAVE_READLINK && HAVE_LSTAT */
}


#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
39742
39743
39744
39745
39746
39747
39748
39749
39750
39751
39752
39753
39754
39755
39756
    const char *path,        /* path for the new unixFile */
    unixFile **ppFile,       /* unixFile created and returned by ref */
    int islockfile           /* if non zero missing dirs will be created */
) {
  int fd = -1;
  unixFile *pNew;
  int rc = SQLITE_OK;
  int openFlags = O_RDWR | O_CREAT;
  sqlite3_vfs dummyVfs;
  int terrno = 0;
  UnixUnusedFd *pUnused = NULL;

  /* 1. first try to open/create the file
  ** 2. if that fails, and this is a lock file (not-conch), try creating
  ** the parent directories and then try again.







|







40250
40251
40252
40253
40254
40255
40256
40257
40258
40259
40260
40261
40262
40263
40264
    const char *path,        /* path for the new unixFile */
    unixFile **ppFile,       /* unixFile created and returned by ref */
    int islockfile           /* if non zero missing dirs will be created */
) {
  int fd = -1;
  unixFile *pNew;
  int rc = SQLITE_OK;
  int openFlags = O_RDWR | O_CREAT | O_NOFOLLOW;
  sqlite3_vfs dummyVfs;
  int terrno = 0;
  UnixUnusedFd *pUnused = NULL;

  /* 1. first try to open/create the file
  ** 2. if that fails, and this is a lock file (not-conch), try creating
  ** the parent directories and then try again.
39772
39773
39774
39775
39776
39777
39778
39779
39780
39781
39782
39783
39784
39785
39786
    if( fd<0 && errno==ENOENT && islockfile ){
      if( proxyCreateLockPath(path) == SQLITE_OK ){
        fd = robust_open(path, openFlags, 0);
      }
    }
  }
  if( fd<0 ){
    openFlags = O_RDONLY;
    fd = robust_open(path, openFlags, 0);
    terrno = errno;
  }
  if( fd<0 ){
    if( islockfile ){
      return SQLITE_BUSY;
    }







|







40280
40281
40282
40283
40284
40285
40286
40287
40288
40289
40290
40291
40292
40293
40294
    if( fd<0 && errno==ENOENT && islockfile ){
      if( proxyCreateLockPath(path) == SQLITE_OK ){
        fd = robust_open(path, openFlags, 0);
      }
    }
  }
  if( fd<0 ){
    openFlags = O_RDONLY | O_NOFOLLOW;
    fd = robust_open(path, openFlags, 0);
    terrno = errno;
  }
  if( fd<0 ){
    if( islockfile ){
      return SQLITE_BUSY;
    }
39898
39899
39900
39901
39902
39903
39904
39905
39906
39907
39908
39909
39910
39911
39912
  /* read the conch content */
  readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
  if( readLen<PROXY_PATHINDEX ){
    sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
    goto end_breaklock;
  }
  /* write it out to the temporary break file */
  fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0);
  if( fd<0 ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
    goto end_breaklock;
  }
  if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
    goto end_breaklock;







|







40406
40407
40408
40409
40410
40411
40412
40413
40414
40415
40416
40417
40418
40419
40420
  /* read the conch content */
  readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
  if( readLen<PROXY_PATHINDEX ){
    sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
    goto end_breaklock;
  }
  /* write it out to the temporary break file */
  fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW), 0);
  if( fd<0 ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
    goto end_breaklock;
  }
  if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
    goto end_breaklock;
41058
41059
41060
41061
41062
41063
41064
41065
41066
41067
41068
41069
41070
41071
41072
41073
41074
41075
41076
41077
41078
41079
#  define NTDDI_WINBLUE                     0x06030000
#endif

#ifndef NTDDI_WINTHRESHOLD
#  define NTDDI_WINTHRESHOLD                0x06040000
#endif

/*
** This constant is needed by the winAccess function; therefore, define
** it when it is missing from the SDK header files.
*/
#ifndef FILE_ATTRIBUTE_REPARSE_POINT
#  define FILE_ATTRIBUTE_REPARSE_POINT      0x00000400
#endif

/*
** Check to see if the GetVersionEx[AW] functions are deprecated on the
** target system.  GetVersionEx was first deprecated in Win8.1.
*/
#ifndef SQLITE_WIN32_GETVERSIONEX
#  if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE
#    define SQLITE_WIN32_GETVERSIONEX   0   /* GetVersionEx() is deprecated */







<
<
<
<
<
<
<
<







41566
41567
41568
41569
41570
41571
41572








41573
41574
41575
41576
41577
41578
41579
#  define NTDDI_WINBLUE                     0x06030000
#endif

#ifndef NTDDI_WINTHRESHOLD
#  define NTDDI_WINTHRESHOLD                0x06040000
#endif









/*
** Check to see if the GetVersionEx[AW] functions are deprecated on the
** target system.  GetVersionEx was first deprecated in Win8.1.
*/
#ifndef SQLITE_WIN32_GETVERSIONEX
#  if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE
#    define SQLITE_WIN32_GETVERSIONEX   0   /* GetVersionEx() is deprecated */
46458
46459
46460
46461
46462
46463
46464
46465
46466
46467
46468
46469
46470
46471
46472
46473
46474
46475
    case SQLITE_ACCESS_EXISTS:
      rc = attr!=INVALID_FILE_ATTRIBUTES;
      break;
    case SQLITE_ACCESS_READWRITE:
      rc = attr!=INVALID_FILE_ATTRIBUTES &&
             (attr & FILE_ATTRIBUTE_READONLY)==0;
      break;
    case SQLITE_ACCESS_SYMLINK:
      rc = attr!=INVALID_FILE_ATTRIBUTES &&
             (attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0;
      break;
    default:
      assert(!"Invalid flags argument");
  }
  *pResOut = rc;
  OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
           zFilename, pResOut, *pResOut));
  return SQLITE_OK;







<
<
<
<







46958
46959
46960
46961
46962
46963
46964




46965
46966
46967
46968
46969
46970
46971
    case SQLITE_ACCESS_EXISTS:
      rc = attr!=INVALID_FILE_ATTRIBUTES;
      break;
    case SQLITE_ACCESS_READWRITE:
      rc = attr!=INVALID_FILE_ATTRIBUTES &&
             (attr & FILE_ATTRIBUTE_READONLY)==0;
      break;




    default:
      assert(!"Invalid flags argument");
  }
  *pResOut = rc;
  OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
           zFilename, pResOut, *pResOut));
  return SQLITE_OK;
49501
49502
49503
49504
49505
49506
49507
49508
49509
49510
49511
49512
49513
49514



49515
49516
49517
49518
49519
49520
49521
    if( !pPg || !p ){
      pcache1Free(pPg);
      sqlite3_free(p);
      pPg = 0;
    }
#else
    pPg = pcache1Alloc(pCache->szAlloc);
    p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
    if( benignMalloc ){ sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
    pcache1EnterMutex(pCache->pGroup);
#endif
    if( pPg==0 ) return 0;



    p->page.pBuf = pPg;
    p->page.pExtra = &p[1];
    p->isBulkLocal = 0;
    p->isAnchor = 0;
  }
  (*pCache->pnPurgeable)++;
  return p;







<






>
>
>







49997
49998
49999
50000
50001
50002
50003

50004
50005
50006
50007
50008
50009
50010
50011
50012
50013
50014
50015
50016
50017
50018
50019
    if( !pPg || !p ){
      pcache1Free(pPg);
      sqlite3_free(p);
      pPg = 0;
    }
#else
    pPg = pcache1Alloc(pCache->szAlloc);

#endif
    if( benignMalloc ){ sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
    pcache1EnterMutex(pCache->pGroup);
#endif
    if( pPg==0 ) return 0;
#ifndef SQLITE_PCACHE_SEPARATE_HEADER
    p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
    p->page.pBuf = pPg;
    p->page.pExtra = &p[1];
    p->isBulkLocal = 0;
    p->isAnchor = 0;
  }
  (*pCache->pnPurgeable)++;
  return p;
50508
50509
50510
50511
50512
50513
50514
50515
50516
50517
50518
50519
50520
50521
50522
  sqlite3RowSetClear(pArg);
  sqlite3DbFree(((RowSet*)pArg)->db, pArg);
}

/*
** Allocate a new RowSetEntry object that is associated with the
** given RowSet.  Return a pointer to the new and completely uninitialized
** objected.
**
** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
** routine returns NULL.
*/
static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
  assert( p!=0 );
  if( p->nFresh==0 ){  /*OPTIMIZATION-IF-FALSE*/







|







51006
51007
51008
51009
51010
51011
51012
51013
51014
51015
51016
51017
51018
51019
51020
  sqlite3RowSetClear(pArg);
  sqlite3DbFree(((RowSet*)pArg)->db, pArg);
}

/*
** Allocate a new RowSetEntry object that is associated with the
** given RowSet.  Return a pointer to the new and completely uninitialized
** object.
**
** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
** routine returns NULL.
*/
static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
  assert( p!=0 );
  if( p->nFresh==0 ){  /*OPTIMIZATION-IF-FALSE*/
50784
50785
50786
50787
50788
50789
50790
50791
50792
50793
50794
50795
50796
50797
50798
  ** To save unnecessary work, only do this when the batch number changes.
  */
  if( iBatch!=pRowSet->iBatch ){  /*OPTIMIZATION-IF-FALSE*/
    p = pRowSet->pEntry;
    if( p ){
      struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
      if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
        /* Only sort the current set of entiries if they need it */
        p = rowSetEntrySort(p);
      }
      for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
        ppPrevTree = &pTree->pRight;
        if( pTree->pLeft==0 ){
          pTree->pLeft = rowSetListToTree(p);
          break;







|







51282
51283
51284
51285
51286
51287
51288
51289
51290
51291
51292
51293
51294
51295
51296
  ** To save unnecessary work, only do this when the batch number changes.
  */
  if( iBatch!=pRowSet->iBatch ){  /*OPTIMIZATION-IF-FALSE*/
    p = pRowSet->pEntry;
    if( p ){
      struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
      if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
        /* Only sort the current set of entries if they need it */
        p = rowSetEntrySort(p);
      }
      for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
        ppPrevTree = &pTree->pRight;
        if( pTree->pLeft==0 ){
          pTree->pLeft = rowSetListToTree(p);
          break;
51396
51397
51398
51399
51400
51401
51402
51403
51404
51405
51406
51407
51408
51409
51410
51411
51412
51413
51414
51415
51416
51417
51418
51419
51420
51421
51422
51423
** PagerSharedLock() for more detail.
**
** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in 
** PAGER_OPEN state.
*/
#define UNKNOWN_LOCK                (EXCLUSIVE_LOCK+1)

/*
** A macro used for invoking the codec if there is one
*/
#ifdef SQLITE_HAS_CODEC
# define CODEC1(P,D,N,X,E) \
    if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; }
# define CODEC2(P,D,N,X,E,O) \
    if( P->xCodec==0 ){ O=(char*)D; }else \
    if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; }
#else
# define CODEC1(P,D,N,X,E)   /* NO-OP */
# define CODEC2(P,D,N,X,E,O) O=(char*)D
#endif

/*
** The maximum allowed sector size. 64KiB. If the xSectorsize() method 
** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
** This could conceivably cause corruption following a power failure on
** such a system. This is currently an undocumented limit.
*/
#define MAX_SECTOR_SIZE 0x10000







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







51894
51895
51896
51897
51898
51899
51900














51901
51902
51903
51904
51905
51906
51907
** PagerSharedLock() for more detail.
**
** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in 
** PAGER_OPEN state.
*/
#define UNKNOWN_LOCK                (EXCLUSIVE_LOCK+1)















/*
** The maximum allowed sector size. 64KiB. If the xSectorsize() method 
** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
** This could conceivably cause corruption following a power failure on
** such a system. This is currently an undocumented limit.
*/
#define MAX_SECTOR_SIZE 0x10000
51695
51696
51697
51698
51699
51700
51701
51702
51703
51704
51705
51706
51707
51708
51709
51710
51711
51712
51713
51714
  void *pBusyHandlerArg;      /* Context argument for xBusyHandler */
  int aStat[4];               /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
  int nRead;                  /* Database pages read */
#endif
  void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
  int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
#ifdef SQLITE_HAS_CODEC
  void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
  void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
  void (*xCodecFree)(void*);             /* Destructor for the codec */
  void *pCodec;               /* First argument to xCodec... methods */
#endif
  char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */
  PCache *pPCache;            /* Pointer to page cache object */
#ifndef SQLITE_OMIT_WAL
  Wal *pWal;                  /* Write-ahead log used by "journal_mode=wal" */
  char *zWal;                 /* File name for write-ahead log */
#endif
};







<
<
<
<
<
<







52179
52180
52181
52182
52183
52184
52185






52186
52187
52188
52189
52190
52191
52192
  void *pBusyHandlerArg;      /* Context argument for xBusyHandler */
  int aStat[4];               /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
  int nRead;                  /* Database pages read */
#endif
  void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
  int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */






  char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */
  PCache *pPCache;            /* Pointer to page cache object */
#ifndef SQLITE_OMIT_WAL
  Wal *pWal;                  /* Write-ahead log used by "journal_mode=wal" */
  char *zWal;                 /* File name for write-ahead log */
#endif
};
51827
51828
51829
51830
51831
51832
51833
51834
51835
51836
51837
51838
51839
51840
51841
51842
51843
**   * the database file is open,
**   * there are no dirty pages in the cache, and
**   * the desired page is not currently in the wal file.
*/
SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
  if( pPager->fd->pMethods==0 ) return 0;
  if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
#ifdef SQLITE_HAS_CODEC
  if( pPager->xCodec!=0 ) return 0;
#endif
#ifndef SQLITE_OMIT_WAL
  if( pPager->pWal ){
    u32 iRead = 0;
    int rc;
    rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
    return (rc==SQLITE_OK && iRead==0);
  }







<
<
<







52305
52306
52307
52308
52309
52310
52311



52312
52313
52314
52315
52316
52317
52318
**   * the database file is open,
**   * there are no dirty pages in the cache, and
**   * the desired page is not currently in the wal file.
*/
SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
  if( pPager->fd->pMethods==0 ) return 0;
  if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;



#ifndef SQLITE_OMIT_WAL
  if( pPager->pWal ){
    u32 iRead = 0;
    int rc;
    rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
    return (rc==SQLITE_OK && iRead==0);
  }
52063
52064
52065
52066
52067
52068
52069
52070
52071
52072
52073
52074
52075
52076
52077
52078
52079
52080
52081
** Set the Pager.xGet method for the appropriate routine used to fetch
** content from the pager.
*/
static void setGetterMethod(Pager *pPager){
  if( pPager->errCode ){
    pPager->xGet = getPageError;
#if SQLITE_MAX_MMAP_SIZE>0
  }else if( USEFETCH(pPager)
#ifdef SQLITE_HAS_CODEC
   && pPager->xCodec==0
#endif
  ){
    pPager->xGet = getPageMMap;
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
  }else{
    pPager->xGet = getPageNormal;
  }
}








|
<
<
<
<







52538
52539
52540
52541
52542
52543
52544
52545




52546
52547
52548
52549
52550
52551
52552
** Set the Pager.xGet method for the appropriate routine used to fetch
** content from the pager.
*/
static void setGetterMethod(Pager *pPager){
  if( pPager->errCode ){
    pPager->xGet = getPageError;
#if SQLITE_MAX_MMAP_SIZE>0
  }else if( USEFETCH(pPager) ){




    pPager->xGet = getPageMMap;
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
  }else{
    pPager->xGet = getPageNormal;
  }
}

52162
52163
52164
52165
52166
52167
52168

52169
52170
52171
52172
52173
52174
52175
    assert( pPager->eLock>=eLock );
    rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock);
    if( pPager->eLock!=UNKNOWN_LOCK ){
      pPager->eLock = (u8)eLock;
    }
    IOTRACE(("UNLOCK %p %d\n", pPager, eLock))
  }

  return rc;
}

/*
** Lock the database file to level eLock, which must be either SHARED_LOCK,
** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
** Pager.eLock variable to the new locking state. 







>







52633
52634
52635
52636
52637
52638
52639
52640
52641
52642
52643
52644
52645
52646
52647
    assert( pPager->eLock>=eLock );
    rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock);
    if( pPager->eLock!=UNKNOWN_LOCK ){
      pPager->eLock = (u8)eLock;
    }
    IOTRACE(("UNLOCK %p %d\n", pPager, eLock))
  }
  pPager->changeCountDone = pPager->tempFile; /* ticket fb3b3024ea238d5c */
  return rc;
}

/*
** Lock the database file to level eLock, which must be either SHARED_LOCK,
** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
** Pager.eLock variable to the new locking state. 
52883
52884
52885
52886
52887
52888
52889
52890
52891
52892
52893
52894
52895
52896
52897
    }

    /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here
    ** without clearing the error code. This is intentional - the error
    ** code is cleared and the cache reset in the block below.
    */
    assert( pPager->errCode || pPager->eState!=PAGER_ERROR );
    pPager->changeCountDone = 0;
    pPager->eState = PAGER_OPEN;
  }

  /* If Pager.errCode is set, the contents of the pager cache cannot be
  ** trusted. Now that there are no outstanding references to the pager,
  ** it can safely move back to PAGER_OPEN state. This happens in both
  ** normal and exclusive-locking mode.







<







53355
53356
53357
53358
53359
53360
53361

53362
53363
53364
53365
53366
53367
53368
    }

    /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here
    ** without clearing the error code. This is intentional - the error
    ** code is cleared and the cache reset in the block below.
    */
    assert( pPager->errCode || pPager->eState!=PAGER_ERROR );

    pPager->eState = PAGER_OPEN;
  }

  /* If Pager.errCode is set, the contents of the pager cache cannot be
  ** trusted. Now that there are no outstanding references to the pager,
  ** it can safely move back to PAGER_OPEN state. This happens in both
  ** normal and exclusive-locking mode.
53147
53148
53149
53150
53151
53152
53153
53154
53155
53156
53157
53158
53159
53160
53161
    if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
  }

  if( !pPager->exclusiveMode 
   && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
  ){
    rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
    pPager->changeCountDone = 0;
  }
  pPager->eState = PAGER_READER;
  pPager->setMaster = 0;

  return (rc==SQLITE_OK?rc2:rc);
}








<







53618
53619
53620
53621
53622
53623
53624

53625
53626
53627
53628
53629
53630
53631
    if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
  }

  if( !pPager->exclusiveMode 
   && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
  ){
    rc2 = pagerUnlockDb(pPager, SHARED_LOCK);

  }
  pPager->eState = PAGER_READER;
  pPager->setMaster = 0;

  return (rc==SQLITE_OK?rc2:rc);
}

53216
53217
53218
53219
53220
53221
53222
53223
53224
53225
53226
53227
53228
53229
53230
53231
53232
53233
53234
53235
53236
53237
53238
53239
53240
53241
53242
53243
53244
53245
53246
53247
53248
53249
53250
53251
53252
53253
53254
53255
53256
53257
53258
  while( i>0 ){
    cksum += aData[i];
    i -= 200;
  }
  return cksum;
}

/*
** Report the current page size and number of reserved bytes back
** to the codec.
*/
#ifdef SQLITE_HAS_CODEC
static void pagerReportSize(Pager *pPager){
  if( pPager->xCodecSizeChng ){
    pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
                           (int)pPager->nReserve);
  }
}
#else
# define pagerReportSize(X)     /* No-op if we do not support a codec */
#endif

#ifdef SQLITE_HAS_CODEC
/*
** Make sure the number of reserved bits is the same in the destination
** pager as it is in the source.  This comes up when a VACUUM changes the
** number of reserved bits to the "optimal" amount.
*/
SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
  if( pDest->nReserve!=pSrc->nReserve ){
    pDest->nReserve = pSrc->nReserve;
    pagerReportSize(pDest);
  }
}
#endif

/*
** Read a single page from either the journal file (if isMainJrnl==1) or
** from the sub-journal (if isMainJrnl==0) and playback that page.
** The page begins at offset *pOffset into the file. The *pOffset
** value is increased to the start of the next page in the journal.
**
** The main rollback journal uses checksums - the statement journal does 







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







53686
53687
53688
53689
53690
53691
53692





























53693
53694
53695
53696
53697
53698
53699
  while( i>0 ){
    cksum += aData[i];
    i -= 200;
  }
  return cksum;
}






























/*
** Read a single page from either the journal file (if isMainJrnl==1) or
** from the sub-journal (if isMainJrnl==0) and playback that page.
** The page begins at offset *pOffset into the file. The *pOffset
** value is increased to the start of the next page in the journal.
**
** The main rollback journal uses checksums - the statement journal does 
53296
53297
53298
53299
53300
53301
53302
53303
53304
53305
53306
53307
53308
53309
53310
53311
53312
53313
53314
  int rc;
  PgHdr *pPg;                   /* An existing page in the cache */
  Pgno pgno;                    /* The page number of a page in journal */
  u32 cksum;                    /* Checksum used for sanity checking */
  char *aData;                  /* Temporary storage for the page */
  sqlite3_file *jfd;            /* The file descriptor for the journal file */
  int isSynced;                 /* True if journal page is synced */
#ifdef SQLITE_HAS_CODEC
  /* The jrnlEnc flag is true if Journal pages should be passed through
  ** the codec.  It is false for pure in-memory journals. */
  const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
#endif

  assert( (isMainJrnl&~1)==0 );      /* isMainJrnl is 0 or 1 */
  assert( (isSavepnt&~1)==0 );       /* isSavepnt is 0 or 1 */
  assert( isMainJrnl || pDone );     /* pDone always used on sub-journals */
  assert( isSavepnt || pDone==0 );   /* pDone never used on non-savepoint */

  aData = pPager->pTmpSpace;







<
<
<
<
<







53737
53738
53739
53740
53741
53742
53743





53744
53745
53746
53747
53748
53749
53750
  int rc;
  PgHdr *pPg;                   /* An existing page in the cache */
  Pgno pgno;                    /* The page number of a page in journal */
  u32 cksum;                    /* Checksum used for sanity checking */
  char *aData;                  /* Temporary storage for the page */
  sqlite3_file *jfd;            /* The file descriptor for the journal file */
  int isSynced;                 /* True if journal page is synced */






  assert( (isMainJrnl&~1)==0 );      /* isMainJrnl is 0 or 1 */
  assert( (isSavepnt&~1)==0 );       /* isSavepnt is 0 or 1 */
  assert( isMainJrnl || pDone );     /* pDone always used on sub-journals */
  assert( isSavepnt || pDone==0 );   /* pDone never used on non-savepoint */

  aData = pPager->pTmpSpace;
53363
53364
53365
53366
53367
53368
53369
53370
53371
53372
53373
53374
53375
53376
53377
    return rc;
  }

  /* When playing back page 1, restore the nReserve setting
  */
  if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
    pPager->nReserve = ((u8*)aData)[20];
    pagerReportSize(pPager);
  }

  /* If the pager is in CACHEMOD state, then there must be a copy of this
  ** page in the pager cache. In this case just update the pager cache,
  ** not the database file. The page is left marked dirty in this case.
  **
  ** An exception to the above rule: If the database is in no-sync mode







<







53799
53800
53801
53802
53803
53804
53805

53806
53807
53808
53809
53810
53811
53812
    return rc;
  }

  /* When playing back page 1, restore the nReserve setting
  */
  if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
    pPager->nReserve = ((u8*)aData)[20];

  }

  /* If the pager is in CACHEMOD state, then there must be a copy of this
  ** page in the pager cache. In this case just update the pager cache,
  ** not the database file. The page is left marked dirty in this case.
  **
  ** An exception to the above rule: If the database is in no-sync mode
53431
53432
53433
53434
53435
53436
53437
53438
53439
53440
53441
53442
53443
53444
53445
53446
53447
53448
53449
53450
53451
53452
53453
53454
53455
53456
53457
53458
53459
53460
53461
53462
53463
53464

    /* Write the data read from the journal back into the database file.
    ** This is usually safe even for an encrypted database - as the data
    ** was encrypted before it was written to the journal file. The exception
    ** is if the data was just read from an in-memory sub-journal. In that
    ** case it must be encrypted here before it is copied into the database
    ** file.  */
#ifdef SQLITE_HAS_CODEC
    if( !jrnlEnc ){
      CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
      rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
      CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
    }else
#endif
    rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);

    if( pgno>pPager->dbFileSize ){
      pPager->dbFileSize = pgno;
    }
    if( pPager->pBackup ){
#ifdef SQLITE_HAS_CODEC
      if( jrnlEnc ){
        CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
        sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
        CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);
      }else
#endif
      sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
    }
  }else if( !isMainJrnl && pPg==0 ){
    /* If this is a rollback of a savepoint and data was not written to
    ** the database and the page is not in-memory, there is a potential
    ** problem. When the page is next fetched by the b-tree layer, it 
    ** will be read from the database file, which may or may not be 







<
<
<
<
<
<
<






<
<
<
<
<
<
<







53866
53867
53868
53869
53870
53871
53872







53873
53874
53875
53876
53877
53878







53879
53880
53881
53882
53883
53884
53885

    /* Write the data read from the journal back into the database file.
    ** This is usually safe even for an encrypted database - as the data
    ** was encrypted before it was written to the journal file. The exception
    ** is if the data was just read from an in-memory sub-journal. In that
    ** case it must be encrypted here before it is copied into the database
    ** file.  */







    rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);

    if( pgno>pPager->dbFileSize ){
      pPager->dbFileSize = pgno;
    }
    if( pPager->pBackup ){







      sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
    }
  }else if( !isMainJrnl && pPg==0 ){
    /* If this is a rollback of a savepoint and data was not written to
    ** the database and the page is not in-memory, there is a potential
    ** problem. When the page is next fetched by the b-tree layer, it 
    ** will be read from the database file, which may or may not be 
53501
53502
53503
53504
53505
53506
53507
53508
53509
53510
53511
53512
53513
53514
53515
53516
53517
53518
53519
    pager_set_pagehash(pPg);

    /* If this was page 1, then restore the value of Pager.dbFileVers.
    ** Do this before any decoding. */
    if( pgno==1 ){
      memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
    }

    /* Decode the page just read from disk */
#if SQLITE_HAS_CODEC
    if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); }
#endif
    sqlite3PcacheRelease(pPg);
  }
  return rc;
}

/*
** Parameter zMaster is the name of a master journal file. A single journal







<
<
<
<
<







53922
53923
53924
53925
53926
53927
53928





53929
53930
53931
53932
53933
53934
53935
    pager_set_pagehash(pPg);

    /* If this was page 1, then restore the value of Pager.dbFileVers.
    ** Do this before any decoding. */
    if( pgno==1 ){
      memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
    }





    sqlite3PcacheRelease(pPg);
  }
  return rc;
}

/*
** Parameter zMaster is the name of a master journal file. A single journal
54065
54066
54067
54068
54069
54070
54071
54072
54073
54074
54075
54076
54077
54078
54079
54080
      */
      memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
    }else{
      u8 *dbFileVers = &((u8*)pPg->pData)[24];
      memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
    }
  }
  CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT);

  PAGER_INCR(sqlite3_pager_readdb_count);
  PAGER_INCR(pPager->nRead);
  IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
  PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
               PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)));

  return rc;







<
<







54481
54482
54483
54484
54485
54486
54487


54488
54489
54490
54491
54492
54493
54494
      */
      memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
    }else{
      u8 *dbFileVers = &((u8*)pPg->pData)[24];
      memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
    }
  }


  PAGER_INCR(sqlite3_pager_readdb_count);
  PAGER_INCR(pPager->nRead);
  IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
  PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
               PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)));

  return rc;
54810
54811
54812
54813
54814
54815
54816
54817
54818
54819
54820
54821
54822
54823
54824
  }

  *pPageSize = pPager->pageSize;
  if( rc==SQLITE_OK ){
    if( nReserve<0 ) nReserve = pPager->nReserve;
    assert( nReserve>=0 && nReserve<1000 );
    pPager->nReserve = (i16)nReserve;
    pagerReportSize(pPager);
    pagerFixMaplimit(pPager);
  }
  return rc;
}

/*
** Return a pointer to the "temporary page" buffer held internally







<







55224
55225
55226
55227
55228
55229
55230

55231
55232
55233
55234
55235
55236
55237
  }

  *pPageSize = pPager->pageSize;
  if( rc==SQLITE_OK ){
    if( nReserve<0 ) nReserve = pPager->nReserve;
    assert( nReserve>=0 && nReserve<1000 );
    pPager->nReserve = (i16)nReserve;

    pagerFixMaplimit(pPager);
  }
  return rc;
}

/*
** Return a pointer to the "temporary page" buffer held internally
55206
55207
55208
55209
55210
55211
55212
55213
55214
55215
55216
55217
55218
55219
55220
55221
55222
55223
55224
  enable_simulated_io_errors();
  PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
  IOTRACE(("CLOSE %p\n", pPager))
  sqlite3OsClose(pPager->jfd);
  sqlite3OsClose(pPager->fd);
  sqlite3PageFree(pTmp);
  sqlite3PcacheClose(pPager->pPCache);

#ifdef SQLITE_HAS_CODEC
  if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
#endif

  assert( !pPager->aSavepoint && !pPager->pInJournal );
  assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );

  sqlite3_free(pPager);
  return SQLITE_OK;
}








<
<
<
<
<







55619
55620
55621
55622
55623
55624
55625





55626
55627
55628
55629
55630
55631
55632
  enable_simulated_io_errors();
  PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
  IOTRACE(("CLOSE %p\n", pPager))
  sqlite3OsClose(pPager->jfd);
  sqlite3OsClose(pPager->fd);
  sqlite3PageFree(pTmp);
  sqlite3PcacheClose(pPager->pPCache);





  assert( !pPager->aSavepoint && !pPager->pInJournal );
  assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );

  sqlite3_free(pPager);
  return SQLITE_OK;
}

55461
55462
55463
55464
55465
55466
55467
55468
55469
55470
55471
55472
55473
55474
55475
55476
    if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
      i64 offset = (pgno-1)*(i64)pPager->pageSize;   /* Offset to write */
      char *pData;                                   /* Data to write */    

      assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
      if( pList->pgno==1 ) pager_write_changecounter(pList);

      /* Encode the database */
      CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);

      /* Write out the page data. */
      rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);

      /* If page 1 was just written, update Pager.dbFileVers to match
      ** the value now stored in the database file. If writing this 
      ** page caused the database file to grow, update dbFileSize. 







<
|







55869
55870
55871
55872
55873
55874
55875

55876
55877
55878
55879
55880
55881
55882
55883
    if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
      i64 offset = (pgno-1)*(i64)pPager->pageSize;   /* Offset to write */
      char *pData;                                   /* Data to write */    

      assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
      if( pList->pgno==1 ) pager_write_changecounter(pList);


      pData = pList->pData;

      /* Write out the page data. */
      rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);

      /* If page 1 was just written, update Pager.dbFileVers to match
      ** the value now stored in the database file. If writing this 
      ** page caused the database file to grow, update dbFileSize. 
55551
55552
55553
55554
55555
55556
55557
55558
55559
55560
55561
55562
55563
55564
55565
55566
55567
55568
55569
55570

    /* If the sub-journal was opened successfully (or was already open),
    ** write the journal record into the file.  */
    if( rc==SQLITE_OK ){
      void *pData = pPg->pData;
      i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
      char *pData2;

#if SQLITE_HAS_CODEC   
      if( !pPager->subjInMemory ){
        CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
      }else
#endif
      pData2 = pData;
      PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
      rc = write32bits(pPager->sjfd, offset, pPg->pgno);
      if( rc==SQLITE_OK ){
        rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
      }
    }







<
<
<
<
<
<







55958
55959
55960
55961
55962
55963
55964






55965
55966
55967
55968
55969
55970
55971

    /* If the sub-journal was opened successfully (or was already open),
    ** write the journal record into the file.  */
    if( rc==SQLITE_OK ){
      void *pData = pPg->pData;
      i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
      char *pData2;






      pData2 = pData;
      PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
      rc = write32bits(pPager->sjfd, offset, pPg->pgno);
      if( rc==SQLITE_OK ){
        rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
      }
    }
55780
55781
55782
55783
55784
55785
55786
55787
55788
55789
55790
55791
55792
55793
55794
55795
55796
55797
55798
55799









55800
55801
55802
55803
55804
55805
55806
55807
55808
55809
55810
55811
55812
55813
55814

  /* Compute and store the full pathname in an allocated buffer pointed
  ** to by zPathname, length nPathname. Or, if this is a temporary file,
  ** leave both nPathname and zPathname set to 0.
  */
  if( zFilename && zFilename[0] ){
    const char *z;
    if( (vfsFlags & SQLITE_OPEN_NOFOLLOW)!=0 ){
      int isLink = 0;
      int rc = sqlite3OsAccess(pVfs, zFilename, SQLITE_ACCESS_SYMLINK, &isLink);
      if( rc==SQLITE_OK && isLink ) rc = SQLITE_CANTOPEN_SYMLINK;
      if( rc ) return rc;
    }
    nPathname = pVfs->mxPathname+1;
    zPathname = sqlite3DbMallocRaw(0, nPathname*2);
    if( zPathname==0 ){
      return SQLITE_NOMEM_BKPT;
    }
    zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
    rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);









    nPathname = sqlite3Strlen30(zPathname);
    z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1];
    while( *z ){
      z += strlen(z)+1;
      z += strlen(z)+1;
      nUri++;
    }
    nUriByte = (int)(&z[2] - zUri);
    assert( nUriByte>=1 );
    if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
      /* This branch is taken when the journal path required by
      ** the database being opened will be more than pVfs->mxPathname
      ** bytes in length. This means the database cannot be opened,
      ** as it will not be possible to open the journal file or even
      ** check for a hot-journal before reading.







<
<
<
<
<
<







>
>
>
>
>
>
>
>
>







|







56181
56182
56183
56184
56185
56186
56187






56188
56189
56190
56191
56192
56193
56194
56195
56196
56197
56198
56199
56200
56201
56202
56203
56204
56205
56206
56207
56208
56209
56210
56211
56212
56213
56214
56215
56216
56217
56218

  /* Compute and store the full pathname in an allocated buffer pointed
  ** to by zPathname, length nPathname. Or, if this is a temporary file,
  ** leave both nPathname and zPathname set to 0.
  */
  if( zFilename && zFilename[0] ){
    const char *z;






    nPathname = pVfs->mxPathname+1;
    zPathname = sqlite3DbMallocRaw(0, nPathname*2);
    if( zPathname==0 ){
      return SQLITE_NOMEM_BKPT;
    }
    zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
    rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
    if( rc!=SQLITE_OK ){
      if( rc==SQLITE_OK_SYMLINK ){
        if( vfsFlags & SQLITE_OPEN_NOFOLLOW ){
          rc = SQLITE_CANTOPEN_SYMLINK;
        }else{
          rc = SQLITE_OK;
        }
      }
    }
    nPathname = sqlite3Strlen30(zPathname);
    z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1];
    while( *z ){
      z += strlen(z)+1;
      z += strlen(z)+1;
      nUri++;
    }
    nUriByte = (int)(&z[1] - zUri);
    assert( nUriByte>=1 );
    if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
      /* This branch is taken when the journal path required by
      ** the database being opened will be more than pVfs->mxPathname
      ** bytes in length. This means the database cannot be opened,
      ** as it will not be possible to open the journal file or even
      ** check for a hot-journal before reading.
55826
55827
55828
55829
55830
55831
55832

55833

55834





























55835
55836
55837
55838
55839
55840

55841

55842
55843
55844
55845

55846
55847
55848
55849
55850
55851
55852
55853
55854

55855
55856
55857
55858
55859
55860

55861
55862
55863






55864



55865
55866






55867

55868
55869


55870
55871
55872

55873
55874
55875
55876

55877
55878
55879



55880
55881
55882
55883
55884
55885
55886
  ** file name. The layout in memory is as follows:
  **
  **     Pager object                    (sizeof(Pager) bytes)
  **     PCache object                   (sqlite3PcacheSize() bytes)
  **     Database file handle            (pVfs->szOsFile bytes)
  **     Sub-journal file handle         (journalFileSize bytes)
  **     Main journal file handle        (journalFileSize bytes)

  **     Database file name              (nPathname+1 bytes)

  **     Journal file name               (nPathname+8+1 bytes)





























  */
  pPtr = (u8 *)sqlite3MallocZero(
    ROUND8(sizeof(*pPager)) +      /* Pager structure */
    ROUND8(pcacheSize) +           /* PCache object */
    ROUND8(pVfs->szOsFile) +       /* The main db file */
    journalFileSize * 2 +          /* The two journal files */ 

    nPathname + 1 + nUriByte +     /* zFilename */

    nPathname + 8 + 2              /* zJournal */
#ifndef SQLITE_OMIT_WAL
    + nPathname + 4 + 2            /* zWal */
#endif

  );
  assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
  if( !pPtr ){
    sqlite3DbFree(0, zPathname);
    return SQLITE_NOMEM_BKPT;
  }
  pPager =              (Pager*)(pPtr);
  pPager->pPCache =    (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
  pPager->fd =   (sqlite3_file*)(pPtr += ROUND8(pcacheSize));

  pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile));
  pPager->jfd =  (sqlite3_file*)(pPtr += journalFileSize);
  pPager->zFilename =    (char*)(pPtr += journalFileSize);
  assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );

  /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */

  if( zPathname ){
    assert( nPathname>0 );
    memcpy(pPager->zFilename, zPathname, nPathname);






    if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUriByte);



    pPager->zJournal =   (char*)(pPtr += nPathname + 1 + nUriByte);
    memcpy(pPager->zJournal, zPathname, nPathname);






    memcpy(&pPager->zJournal[nPathname], "-journal", 8);

    sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
#ifndef SQLITE_OMIT_WAL


    pPager->zWal = (char*)(pPtr += nPathname + 8 + 2);
    memcpy(pPager->zWal, zPathname, nPathname);
    memcpy(&pPager->zWal[nPathname], "-wal", 4);

    sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
    assert( sqlite3UriCount(pPager->zWal)==0 );
#endif
    assert( sqlite3UriCount(pPager->zFilename)==nUri );

    assert( sqlite3UriCount(pPager->zJournal)==0 );
    sqlite3DbFree(0, zPathname);
  }



  pPager->pVfs = pVfs;
  pPager->vfsFlags = vfsFlags;

  /* Open the pager file.
  */
  if( zFilename && zFilename[0] ){
    int fout = 0;                    /* VFS flags returned by xOpen() */







>

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


|
|
|
|
>
|
>
|

|

>






<
|
|
>
|
|
<


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

>
>
|
|
|
>
|
|

<
>
|
<

>
>
>







56230
56231
56232
56233
56234
56235
56236
56237
56238
56239
56240
56241
56242
56243
56244
56245
56246
56247
56248
56249
56250
56251
56252
56253
56254
56255
56256
56257
56258
56259
56260
56261
56262
56263
56264
56265
56266
56267
56268
56269
56270
56271
56272
56273
56274
56275
56276
56277
56278
56279
56280
56281
56282
56283
56284
56285
56286
56287
56288
56289

56290
56291
56292
56293
56294

56295
56296
56297
56298
56299
56300
56301
56302
56303
56304
56305
56306
56307
56308
56309
56310
56311
56312
56313
56314
56315
56316
56317
56318
56319
56320
56321
56322
56323
56324
56325
56326
56327
56328
56329
56330
56331
56332

56333
56334

56335
56336
56337
56338
56339
56340
56341
56342
56343
56344
56345
  ** file name. The layout in memory is as follows:
  **
  **     Pager object                    (sizeof(Pager) bytes)
  **     PCache object                   (sqlite3PcacheSize() bytes)
  **     Database file handle            (pVfs->szOsFile bytes)
  **     Sub-journal file handle         (journalFileSize bytes)
  **     Main journal file handle        (journalFileSize bytes)
  **     \0\0\0\0 database prefix        (4 bytes)
  **     Database file name              (nPathname+1 bytes)
  **     URI query parameters            (nUriByte bytes)
  **     Journal filename                (nPathname+8+1 bytes)
  **     WAL filename                    (nPathname+4+1 bytes)
  **     \0\0\0 terminator               (3 bytes)
  **
  ** Some 3rd-party software, over which we have no control, depends on
  ** the specific order of the filenames and the \0 separators between them
  ** so that it can (for example) find the database filename given the WAL
  ** filename without using the sqlite3_filename_database() API.  This is a
  ** misuse of SQLite and a bug in the 3rd-party software, but the 3rd-party
  ** software is in widespread use, so we try to avoid changing the filename
  ** order and formatting if possible.  In particular, the details of the
  ** filename format expected by 3rd-party software should be as follows:
  **
  **   - Main Database Path
  **   - \0
  **   - Multiple URI components consisting of:
  **     - Key
  **     - \0
  **     - Value
  **     - \0
  **   - \0
  **   - Journal Path
  **   - \0
  **   - WAL Path (zWALName)
  **   - \0
  **
  ** The sqlite3_create_filename() interface and the databaseFilename() utility
  ** that is used by sqlite3_filename_database() and kin also depend on the
  ** specific formatting and order of the various filenames, so if the format
  ** changes here, be sure to change it there as well.
  */
  pPtr = (u8 *)sqlite3MallocZero(
    ROUND8(sizeof(*pPager)) +            /* Pager structure */
    ROUND8(pcacheSize) +                 /* PCache object */
    ROUND8(pVfs->szOsFile) +             /* The main db file */
    journalFileSize * 2 +                /* The two journal files */
    4 +                                  /* Database prefix */
    nPathname + 1 +                      /* database filename */
    nUriByte +                           /* query parameters */
    nPathname + 8 + 1 +                  /* Journal filename */
#ifndef SQLITE_OMIT_WAL
    nPathname + 4 + 1 +                  /* WAL filename */
#endif
    3                                    /* Terminator */
  );
  assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
  if( !pPtr ){
    sqlite3DbFree(0, zPathname);
    return SQLITE_NOMEM_BKPT;
  }

  pPager = (Pager*)pPtr;                  pPtr += ROUND8(sizeof(*pPager));
  pPager->pPCache = (PCache*)pPtr;        pPtr += ROUND8(pcacheSize);
  pPager->fd = (sqlite3_file*)pPtr;       pPtr += ROUND8(pVfs->szOsFile);
  pPager->sjfd = (sqlite3_file*)pPtr;     pPtr += journalFileSize;
  pPager->jfd =  (sqlite3_file*)pPtr;     pPtr += journalFileSize;

  assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );

  /* Fill in the Pager.zFilename and pPager.zQueryParam fields */
                                          pPtr += 4;  /* Skip zero prefix */
  pPager->zFilename = (char*)pPtr;
  if( nPathname>0 ){
    memcpy(pPtr, zPathname, nPathname);   pPtr += nPathname + 1;
    if( zUri ){
      memcpy(pPtr, zUri, nUriByte);       pPtr += nUriByte;
    }else{
                                          pPtr++;
    }
  }


  /* Fill in Pager.zJournal */
  if( nPathname>0 ){
    pPager->zJournal = (char*)pPtr;
    memcpy(pPtr, zPathname, nPathname);   pPtr += nPathname;
    memcpy(pPtr, "-journal",8);           pPtr += 8 + 1;
#ifdef SQLITE_ENABLE_8_3_NAMES
    sqlite3FileSuffix3(zFilename,pPager->zJournal);
    pPtr = (u8*)(pPager->zJournal + sqlite3Strlen30(pPager->zJournal)+1);
#endif
  }else{
    pPager->zJournal = 0;
  }

#ifndef SQLITE_OMIT_WAL
  /* Fill in Pager.zWal */
  if( nPathname>0 ){
    pPager->zWal = (char*)pPtr;
    memcpy(pPtr, zPathname, nPathname);   pPtr += nPathname;
    memcpy(pPtr, "-wal", 4);              pPtr += 4 + 1;
#ifdef SQLITE_ENABLE_8_3_NAMES
    sqlite3FileSuffix3(zFilename, pPager->zWal);
    pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1);
#endif

  }else{
    pPager->zWal = 0;

  }
#endif

  if( nPathname ) sqlite3DbFree(0, zPathname);
  pPager->pVfs = pVfs;
  pPager->vfsFlags = vfsFlags;

  /* Open the pager file.
  */
  if( zFilename && zFilename[0] ){
    int fout = 0;                    /* VFS flags returned by xOpen() */
55921
55922
55923
55924
55925
55926
55927
55928
55929
55930
55931
55932
55933
55934
55935
55936
55937
            if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){
              szPageDflt = ii;
            }
          }
        }
#endif
      }
      pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0);
      if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0
       || sqlite3_uri_boolean(zFilename, "immutable", 0) ){
          vfsFlags |= SQLITE_OPEN_READONLY;
          goto act_like_temp_file;
      }
    }
  }else{
    /* If a temporary file is requested, it is not opened immediately.
    ** In this case we accept the default page size and delay actually







|

|







56380
56381
56382
56383
56384
56385
56386
56387
56388
56389
56390
56391
56392
56393
56394
56395
56396
            if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){
              szPageDflt = ii;
            }
          }
        }
#endif
      }
      pPager->noLock = sqlite3_uri_boolean(pPager->zFilename, "nolock", 0);
      if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0
       || sqlite3_uri_boolean(pPager->zFilename, "immutable", 0) ){
          vfsFlags |= SQLITE_OPEN_READONLY;
          goto act_like_temp_file;
      }
    }
  }else{
    /* If a temporary file is requested, it is not opened immediately.
    ** In this case we accept the default page size and delay actually
56585
56586
56587
56588
56589
56590
56591
56592
56593
56594
56595
56596
56597
56598
56599
56600
56601
  ** flag was specified by the caller. And so long as the db is not a 
  ** temporary or in-memory database.  */
  const int bMmapOk = (pgno>1
   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
  );

  assert( USEFETCH(pPager) );
#ifdef SQLITE_HAS_CODEC
  assert( pPager->xCodec==0 );
#endif

  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
  ** allows the compiler optimizer to reuse the results of the "pgno>1"
  ** test in the previous statement, and avoid testing pgno==0 in the
  ** common case where pgno is large. */
  if( pgno<=1 && pgno==0 ){
    return SQLITE_CORRUPT_BKPT;







<
<
<







57044
57045
57046
57047
57048
57049
57050



57051
57052
57053
57054
57055
57056
57057
  ** flag was specified by the caller. And so long as the db is not a 
  ** temporary or in-memory database.  */
  const int bMmapOk = (pgno>1
   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
  );

  assert( USEFETCH(pPager) );




  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
  ** allows the compiler optimizer to reuse the results of the "pgno>1"
  ** test in the previous statement, and avoid testing pgno==0 in the
  ** common case where pgno is large. */
  if( pgno<=1 && pgno==0 ){
    return SQLITE_CORRUPT_BKPT;
56916
56917
56918
56919
56920
56921
56922
56923
56924
56925
56926
56927
56928
56929
56930

  /* We should never write to the journal file the page that
  ** contains the database locks.  The following assert verifies
  ** that we do not. */
  assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );

  assert( pPager->journalHdr<=pPager->journalOff );
  CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
  cksum = pager_cksum(pPager, (u8*)pData2);

  /* Even if an IO or diskfull error occurs while journalling the
  ** page in the block above, set the need-sync flag for the page.
  ** Otherwise, when the transaction is rolled back, the logic in
  ** playback_one_page() will think that the page needs to be restored
  ** in the database file. And if an IO error occurs while doing so,







|







57372
57373
57374
57375
57376
57377
57378
57379
57380
57381
57382
57383
57384
57385
57386

  /* We should never write to the journal file the page that
  ** contains the database locks.  The following assert verifies
  ** that we do not. */
  assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );

  assert( pPager->journalHdr<=pPager->journalOff );
  pData2 = pPg->pData;
  cksum = pager_cksum(pPager, (u8*)pData2);

  /* Even if an IO or diskfull error occurs while journalling the
  ** page in the block above, set the need-sync flag for the page.
  ** Otherwise, when the transaction is rolled back, the logic in
  ** playback_one_page() will think that the page needs to be restored
  ** in the database file. And if an IO error occurs while doing so,
57281
57282
57283
57284
57285
57286
57287
57288
57289
57290
57291
57292
57293
57294
57295
      /* Actually do the update of the change counter */
      pager_write_changecounter(pPgHdr);

      /* If running in direct mode, write the contents of page 1 to the file. */
      if( DIRECT_MODE ){
        const void *zBuf;
        assert( pPager->dbFileSize>0 );
        CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
        if( rc==SQLITE_OK ){
          rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
          pPager->aStat[PAGER_STAT_WRITE]++;
        }
        if( rc==SQLITE_OK ){
          /* Update the pager's copy of the change-counter. Otherwise, the
          ** next time a read transaction is opened the cache will be







|







57737
57738
57739
57740
57741
57742
57743
57744
57745
57746
57747
57748
57749
57750
57751
      /* Actually do the update of the change counter */
      pager_write_changecounter(pPgHdr);

      /* If running in direct mode, write the contents of page 1 to the file. */
      if( DIRECT_MODE ){
        const void *zBuf;
        assert( pPager->dbFileSize>0 );
        zBuf = pPgHdr->pData;
        if( rc==SQLITE_OK ){
          rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
          pPager->aStat[PAGER_STAT_WRITE]++;
        }
        if( rc==SQLITE_OK ){
          /* Update the pager's copy of the change-counter. Otherwise, the
          ** next time a read transaction is opened the cache will be
57614
57615
57616
57617
57618
57619
57620

57621
57622
57623
57624
57625
57626
57627
SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
  int rc = SQLITE_OK;                  /* Return code */

  /* This routine should not be called if a prior error has occurred.
  ** But if (due to a coding error elsewhere in the system) it does get
  ** called, just return the same error code without doing anything. */
  if( NEVER(pPager->errCode) ) return pPager->errCode;


  assert( pPager->eState==PAGER_WRITER_LOCKED
       || pPager->eState==PAGER_WRITER_FINISHED
       || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD)
  );
  assert( assert_pager_state(pPager) );








>







58070
58071
58072
58073
58074
58075
58076
58077
58078
58079
58080
58081
58082
58083
58084
SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
  int rc = SQLITE_OK;                  /* Return code */

  /* This routine should not be called if a prior error has occurred.
  ** But if (due to a coding error elsewhere in the system) it does get
  ** called, just return the same error code without doing anything. */
  if( NEVER(pPager->errCode) ) return pPager->errCode;
  pPager->iDataVersion++;

  assert( pPager->eState==PAGER_WRITER_LOCKED
       || pPager->eState==PAGER_WRITER_FINISHED
       || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD)
  );
  assert( assert_pager_state(pPager) );

57642
57643
57644
57645
57646
57647
57648
57649
57650
57651
57652
57653
57654
57655
57656
  ){
    assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
    pPager->eState = PAGER_READER;
    return SQLITE_OK;
  }

  PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
  pPager->iDataVersion++;
  rc = pager_end_transaction(pPager, pPager->setMaster, 1);
  return pager_error(pPager, rc);
}

/*
** If a write transaction is open, then all changes made within the 
** transaction are reverted and the current write-transaction is closed.







<







58099
58100
58101
58102
58103
58104
58105

58106
58107
58108
58109
58110
58111
58112
  ){
    assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
    pPager->eState = PAGER_READER;
    return SQLITE_OK;
  }

  PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));

  rc = pager_end_transaction(pPager, pPager->setMaster, 1);
  return pager_error(pPager, rc);
}

/*
** If a write transaction is open, then all changes made within the 
** transaction are reverted and the current write-transaction is closed.
57986
57987
57988
57989
57990
57991
57992



57993
57994

57995
57996
57997
57998
57999
58000
58001
58002
**
** Except, if the pager is in-memory only, then return an empty string if
** nullIfMemDb is true.  This routine is called with nullIfMemDb==1 when
** used to report the filename to the user, for compatibility with legacy
** behavior.  But when the Btree needs to know the filename for matching to
** shared cache, it uses nullIfMemDb==0 so that in-memory databases can
** participate in shared-cache.



*/
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){

  return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename;
}

/*
** Return the VFS structure for the pager.
*/
SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
  return pPager->pVfs;







>
>
>

|
>
|







58442
58443
58444
58445
58446
58447
58448
58449
58450
58451
58452
58453
58454
58455
58456
58457
58458
58459
58460
58461
58462
**
** Except, if the pager is in-memory only, then return an empty string if
** nullIfMemDb is true.  This routine is called with nullIfMemDb==1 when
** used to report the filename to the user, for compatibility with legacy
** behavior.  But when the Btree needs to know the filename for matching to
** shared cache, it uses nullIfMemDb==0 so that in-memory databases can
** participate in shared-cache.
**
** The return value to this routine is always safe to use with
** sqlite3_uri_parameter() and sqlite3_filename_database() and friends.
*/
SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){
  static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename;
}

/*
** Return the VFS structure for the pager.
*/
SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
  return pPager->pVfs;
58036
58037
58038
58039
58040
58041
58042
58043
58044
58045
58046
58047
58048
58049
58050
58051
58052
58053
58054
58055
58056
58057
58058
58059
58060
58061
58062
58063
58064
58065
58066
58067
58068
58069
58070
58071
58072
58073
58074
58075
58076
58077
58078
58079
58080
58081
58082
58083
58084
58085
58086
58087
58088
58089
58090
58091
58092
58093
58094
58095
58096
58097
/*
** Return the full pathname of the journal file.
*/
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
  return pPager->zJournal;
}

#ifdef SQLITE_HAS_CODEC
/*
** Set or retrieve the codec for this pager
*/
SQLITE_PRIVATE void sqlite3PagerSetCodec(
  Pager *pPager,
  void *(*xCodec)(void*,void*,Pgno,int),
  void (*xCodecSizeChng)(void*,int,int),
  void (*xCodecFree)(void*),
  void *pCodec
){
  if( pPager->xCodecFree ){
    pPager->xCodecFree(pPager->pCodec);
  }else{
    pager_reset(pPager);
  }
  pPager->xCodec = pPager->memDb ? 0 : xCodec;
  pPager->xCodecSizeChng = xCodecSizeChng;
  pPager->xCodecFree = xCodecFree;
  pPager->pCodec = pCodec;
  setGetterMethod(pPager);
  pagerReportSize(pPager);
}
SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
  return pPager->pCodec;
}

/*
** This function is called by the wal module when writing page content
** into the log file.
**
** This function returns a pointer to a buffer containing the encrypted
** page content. If a malloc fails, this function may return NULL.
*/
SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
  void *aData = 0;
  CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
  return aData;
}

/*
** Return the current pager state
*/
SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
  return pPager->eState;
}
#endif /* SQLITE_HAS_CODEC */

#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Move the page pPg to location pgno in the file.
**
** There must be no references to the page previously located at
** pgno (which we call pPgOld) though that page is allowed to be
** in cache.  If the page previously located at pgno is not already







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







58496
58497
58498
58499
58500
58501
58502
















































58503
58504
58505
58506
58507
58508
58509
/*
** Return the full pathname of the journal file.
*/
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
  return pPager->zJournal;
}

















































#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Move the page pPg to location pgno in the file.
**
** There must be no references to the page previously located at
** pgno (which we call pPgOld) though that page is allowed to be
** in cache.  If the page previously located at pgno is not already
58642
58643
58644
58645
58646
58647
58648


58649
58650
58651
58652
58653
58654
58655
      pPager->pWal = 0;
      pagerFixMaplimit(pPager);
      if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
    }
  }
  return rc;
}



#ifdef SQLITE_ENABLE_SNAPSHOT
/*
** If this is a WAL database, obtain a snapshot handle for the snapshot
** currently open. Otherwise, return an error.
*/
SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){







>
>







59054
59055
59056
59057
59058
59059
59060
59061
59062
59063
59064
59065
59066
59067
59068
59069
      pPager->pWal = 0;
      pagerFixMaplimit(pPager);
      if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
    }
  }
  return rc;
}



#ifdef SQLITE_ENABLE_SNAPSHOT
/*
** If this is a WAL database, obtain a snapshot handle for the snapshot
** currently open. Otherwise, return an error.
*/
SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
58997
58998
58999
59000
59001
59002
59003
59004
59005
59006
59007
59008
59009
59010
59011
59012
59013
59014
59015
59016
59017
59018
59019
59020
59021
59022
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
SQLITE_PRIVATE int sqlite3WalTrace = 0;
# define WALTRACE(X)  if(sqlite3WalTrace) sqlite3DebugPrintf X
#else
# define WALTRACE(X)
#endif

/*
** WAL mode depends on atomic aligned 32-bit loads and stores in a few
** places.  The following macros try to make this explicit.
*/
#if GCC_VESRION>=5004000
# define AtomicLoad(PTR)       __atomic_load_n((PTR),__ATOMIC_RELAXED)
# define AtomicStore(PTR,VAL)  __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
#else
# define AtomicLoad(PTR)       (*(PTR))
# define AtomicStore(PTR,VAL)  (*(PTR) = (VAL))
#endif

/*
** The maximum (and only) versions of the wal and wal-index formats
** that may be interpreted by this version of SQLite.
**
** If a client begins recovering a WAL file and finds that (a) the checksum
** values in the wal-header are correct and (b) the version field is not
** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.







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







59411
59412
59413
59414
59415
59416
59417












59418
59419
59420
59421
59422
59423
59424
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
SQLITE_PRIVATE int sqlite3WalTrace = 0;
# define WALTRACE(X)  if(sqlite3WalTrace) sqlite3DebugPrintf X
#else
# define WALTRACE(X)
#endif













/*
** The maximum (and only) versions of the wal and wal-index formats
** that may be interpreted by this version of SQLite.
**
** If a client begins recovering a WAL file and finds that (a) the checksum
** values in the wal-header are correct and (b) the version field is not
** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
59878
59879
59880
59881
59882
59883
59884





59885
59886
59887
59888
59889
59890
59891
** the necessary locks, this routine returns SQLITE_BUSY.
*/
static int walIndexRecover(Wal *pWal){
  int rc;                         /* Return Code */
  i64 nSize;                      /* Size of log file */
  u32 aFrameCksum[2] = {0, 0};
  int iLock;                      /* Lock offset to lock for checkpoint */






  /* Obtain an exclusive lock on all byte in the locking range not already
  ** locked by the caller. The caller is guaranteed to have locked the
  ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
  ** If successful, the same bytes that are locked here are unlocked before
  ** this function returns.
  */







>
>
>
>
>







60280
60281
60282
60283
60284
60285
60286
60287
60288
60289
60290
60291
60292
60293
60294
60295
60296
60297
60298
** the necessary locks, this routine returns SQLITE_BUSY.
*/
static int walIndexRecover(Wal *pWal){
  int rc;                         /* Return Code */
  i64 nSize;                      /* Size of log file */
  u32 aFrameCksum[2] = {0, 0};
  int iLock;                      /* Lock offset to lock for checkpoint */

#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  int tmout = 0;
  sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
#endif

  /* Obtain an exclusive lock on all byte in the locking range not already
  ** locked by the caller. The caller is guaranteed to have locked the
  ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
  ** If successful, the same bytes that are locked here are unlocked before
  ** this function returns.
  */
60563
60564
60565
60566
60567
60568
60569
60570












60571
60572
60573
60574
60575
60576
60577
      /* Thread-sanitizer reports that the following is an unsafe read,
      ** as some other thread may be in the process of updating the value
      ** of the aReadMark[] slot. The assumption here is that if that is
      ** happening, the other client may only be increasing the value,
      ** not decreasing it. So assuming either that either the "old" or
      ** "new" version of the value is read, and not some arbitrary value
      ** that would never be written by a real client, things are still 
      ** safe.  */












      u32 y = pInfo->aReadMark[i];
      if( mxSafeFrame>y ){
        assert( y<=pWal->hdr.mxFrame );
        rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
        if( rc==SQLITE_OK ){
          pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);







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







60970
60971
60972
60973
60974
60975
60976
60977
60978
60979
60980
60981
60982
60983
60984
60985
60986
60987
60988
60989
60990
60991
60992
60993
60994
60995
60996
      /* Thread-sanitizer reports that the following is an unsafe read,
      ** as some other thread may be in the process of updating the value
      ** of the aReadMark[] slot. The assumption here is that if that is
      ** happening, the other client may only be increasing the value,
      ** not decreasing it. So assuming either that either the "old" or
      ** "new" version of the value is read, and not some arbitrary value
      ** that would never be written by a real client, things are still 
      ** safe.
      **
      ** Astute readers have pointed out that the assumption stated in the
      ** last sentence of the previous paragraph is not guaranteed to be
      ** true for all conforming systems.  However, the assumption is true
      ** for all compilers and architectures in common use today (circa
      ** 2019-11-27) and the alternatives are both slow and complex, and
      ** so we will continue to go with the current design for now.  If this
      ** bothers you, or if you really are running on a system where aligned
      ** 32-bit reads and writes are not atomic, then you can simply avoid
      ** the use of WAL mode, or only use WAL mode together with
      ** PRAGMA locking_mode=EXCLUSIVE and all will be well.
      */
      u32 y = pInfo->aReadMark[i];
      if( mxSafeFrame>y ){
        assert( y<=pWal->hdr.mxFrame );
        rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
        if( rc==SQLITE_OK ){
          pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
60613
60614
60615
60616
60617
60618
60619
60620
60621
60622
60623
60624
60625
60626
60627
      }


      /* Iterate through the contents of the WAL, copying data to the db file */
      while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
        i64 iOffset;
        assert( walFramePgno(pWal, iFrame)==iDbpage );
        if( db->u1.isInterrupted ){
          rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
          break;
        }
        if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
          continue;
        }
        iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;







|







61032
61033
61034
61035
61036
61037
61038
61039
61040
61041
61042
61043
61044
61045
61046
      }


      /* Iterate through the contents of the WAL, copying data to the db file */
      while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
        i64 iOffset;
        assert( walFramePgno(pWal, iFrame)==iDbpage );
        if( AtomicLoad(&db->u1.isInterrupted) ){
          rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
          break;
        }
        if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
          continue;
        }
        iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
60640
60641
60642
60643
60644
60645
60646




60647
60648
60649
60650
60651
60652
60653
          i64 szDb = pWal->hdr.nPage*(i64)szPage;
          testcase( IS_BIG_INT(szDb) );
          rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
          if( rc==SQLITE_OK ){
            rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
          }
        }




        if( rc==SQLITE_OK ){
          pInfo->nBackfill = mxSafeFrame;
        }
      }

      /* Release the reader lock held while backfilling */
      walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);







>
>
>
>







61059
61060
61061
61062
61063
61064
61065
61066
61067
61068
61069
61070
61071
61072
61073
61074
61075
61076
          i64 szDb = pWal->hdr.nPage*(i64)szPage;
          testcase( IS_BIG_INT(szDb) );
          rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
          if( rc==SQLITE_OK ){
            rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
          }
        }
        if( rc==SQLITE_OK ){
          rc = sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0);
          if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
        }
        if( rc==SQLITE_OK ){
          pInfo->nBackfill = mxSafeFrame;
        }
      }

      /* Release the reader lock held while backfilling */
      walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
61322
61323
61324
61325
61326
61327
61328
61329

61330
61331
61332
61333
61334
61335
61336
  }
  if( (pWal->readOnly & WAL_SHM_RDONLY)==0
   && (mxReadMark<mxFrame || mxI==0)
  ){
    for(i=1; i<WAL_NREADER; i++){
      rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
      if( rc==SQLITE_OK ){
        mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame);

        mxI = i;
        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
        break;
      }else if( rc!=SQLITE_BUSY ){
        return rc;
      }
    }







|
>







61745
61746
61747
61748
61749
61750
61751
61752
61753
61754
61755
61756
61757
61758
61759
61760
  }
  if( (pWal->readOnly & WAL_SHM_RDONLY)==0
   && (mxReadMark<mxFrame || mxI==0)
  ){
    for(i=1; i<WAL_NREADER; i++){
      rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
      if( rc==SQLITE_OK ){
        AtomicStore(pInfo->aReadMark+i,mxFrame);
        mxReadMark = mxFrame;
        mxI = i;
        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
        break;
      }else if( rc!=SQLITE_BUSY ){
        return rc;
      }
    }
61481
61482
61483
61484
61485
61486
61487



61488
61489
61490
61491
61492
61493
61494
61495
61496






61497
61498
61499
61500
61501
61502
61503










61504
61505
61506
61507
61508
61509
61510
** transaction, then *pChanged is set to 1 before returning.  The
** Pager layer will use this to know that its cache is stale and
** needs to be flushed.
*/
SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
  int rc;                         /* Return code */
  int cnt = 0;                    /* Number of TryBeginRead attempts */




#ifdef SQLITE_ENABLE_SNAPSHOT
  int bChanged = 0;
  WalIndexHdr *pSnapshot = pWal->pSnapshot;
  if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
    bChanged = 1;
  }
#endif







  do{
    rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
  }while( rc==WAL_RETRY );
  testcase( (rc&0xff)==SQLITE_BUSY );
  testcase( (rc&0xff)==SQLITE_IOERR );
  testcase( rc==SQLITE_PROTOCOL );
  testcase( rc==SQLITE_OK );











#ifdef SQLITE_ENABLE_SNAPSHOT
  if( rc==SQLITE_OK ){
    if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
      /* At this point the client has a lock on an aReadMark[] slot holding
      ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
      ** is populated with the wal-index header corresponding to the head







>
>
>









>
>
>
>
>
>







>
>
>
>
>
>
>
>
>
>







61905
61906
61907
61908
61909
61910
61911
61912
61913
61914
61915
61916
61917
61918
61919
61920
61921
61922
61923
61924
61925
61926
61927
61928
61929
61930
61931
61932
61933
61934
61935
61936
61937
61938
61939
61940
61941
61942
61943
61944
61945
61946
61947
61948
61949
61950
61951
61952
61953
** transaction, then *pChanged is set to 1 before returning.  The
** Pager layer will use this to know that its cache is stale and
** needs to be flushed.
*/
SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
  int rc;                         /* Return code */
  int cnt = 0;                    /* Number of TryBeginRead attempts */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  int tmout = 0;
#endif

#ifdef SQLITE_ENABLE_SNAPSHOT
  int bChanged = 0;
  WalIndexHdr *pSnapshot = pWal->pSnapshot;
  if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
    bChanged = 1;
  }
#endif

#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  /* Disable blocking locks. They are not useful when trying to open a
  ** read-transaction, and blocking may cause deadlock anyway. */
  sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
#endif

  do{
    rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
  }while( rc==WAL_RETRY );
  testcase( (rc&0xff)==SQLITE_BUSY );
  testcase( (rc&0xff)==SQLITE_IOERR );
  testcase( rc==SQLITE_PROTOCOL );
  testcase( rc==SQLITE_OK );

#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  /* If they were disabled earlier and the read-transaction has been
  ** successfully opened, re-enable blocking locks. This is because the
  ** connection may attempt to upgrade to a write-transaction, which does
  ** benefit from using blocking locks.  */
  if( rc==SQLITE_OK ){
    sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
  }
#endif

#ifdef SQLITE_ENABLE_SNAPSHOT
  if( rc==SQLITE_OK ){
    if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
      /* At this point the client has a lock on an aReadMark[] slot holding
      ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
      ** is populated with the wal-index header corresponding to the head
61976
61977
61978
61979
61980
61981
61982
61983
61984
61985
61986
61987
61988
61989
61990
61991
61992
61993
61994
  PgHdr *pPage,               /* The page of the frame to be written */
  int nTruncate,              /* The commit flag.  Usually 0.  >0 for commit */
  sqlite3_int64 iOffset       /* Byte offset at which to write */
){
  int rc;                         /* Result code from subfunctions */
  void *pData;                    /* Data actually written */
  u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */
#if defined(SQLITE_HAS_CODEC)
  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
#else
  pData = pPage->pData;
#endif
  walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
  rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
  if( rc ) return rc;
  /* Write the page data */
  rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
  return rc;
}







<
<
<

<







62419
62420
62421
62422
62423
62424
62425



62426

62427
62428
62429
62430
62431
62432
62433
  PgHdr *pPage,               /* The page of the frame to be written */
  int nTruncate,              /* The commit flag.  Usually 0.  >0 for commit */
  sqlite3_int64 iOffset       /* Byte offset at which to write */
){
  int rc;                         /* Result code from subfunctions */
  void *pData;                    /* Data actually written */
  u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */



  pData = pPage->pData;

  walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
  rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
  if( rc ) return rc;
  /* Write the page data */
  rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
  return rc;
}
62163
62164
62165
62166
62167
62168
62169
62170
62171
62172
62173
62174
62175
62176
62177
62178
62179
62180
62181
      assert( rc==SQLITE_OK || iWrite==0 );
      if( iWrite>=iFirst ){
        i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
        void *pData;
        if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
          pWal->iReCksum = iWrite;
        }
#if defined(SQLITE_HAS_CODEC)
        if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
#else
        pData = p->pData;
#endif
        rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
        if( rc ) return rc;
        p->flags &= ~PGHDR_WAL_APPEND;
        continue;
      }
    }








<
<
<

<







62602
62603
62604
62605
62606
62607
62608



62609

62610
62611
62612
62613
62614
62615
62616
      assert( rc==SQLITE_OK || iWrite==0 );
      if( iWrite>=iFirst ){
        i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
        void *pData;
        if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
          pWal->iReCksum = iWrite;
        }



        pData = p->pData;

        rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
        if( rc ) return rc;
        p->flags &= ~PGHDR_WAL_APPEND;
        continue;
      }
    }

63025
63026
63027
63028
63029
63030
63031
63032
63033
63034
63035
63036
63037
63038
63039
63040
63041
#ifndef SQLITE_OMIT_AUTOVACUUM
  u8 autoVacuum;        /* True if auto-vacuum is enabled */
  u8 incrVacuum;        /* True if incr-vacuum is enabled */
  u8 bDoTruncate;       /* True to truncate db on commit */
#endif
  u8 inTransaction;     /* Transaction state */
  u8 max1bytePayload;   /* Maximum first byte of cell for a 1-byte payload */
#ifdef SQLITE_HAS_CODEC
  u8 optimalReserve;    /* Desired amount of reserved space per page */
#endif
  u16 btsFlags;         /* Boolean parameters.  See BTS_* macros below */
  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
  u32 pageSize;         /* Total number of bytes on a page */
  u32 usableSize;       /* Number of usable bytes on each page */







<
|
<







63460
63461
63462
63463
63464
63465
63466

63467

63468
63469
63470
63471
63472
63473
63474
#ifndef SQLITE_OMIT_AUTOVACUUM
  u8 autoVacuum;        /* True if auto-vacuum is enabled */
  u8 incrVacuum;        /* True if incr-vacuum is enabled */
  u8 bDoTruncate;       /* True to truncate db on commit */
#endif
  u8 inTransaction;     /* Transaction state */
  u8 max1bytePayload;   /* Maximum first byte of cell for a 1-byte payload */

  u8 nReserveWanted;    /* 1 more than desired number of extra bytes per page */

  u16 btsFlags;         /* Boolean parameters.  See BTS_* macros below */
  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
  u32 pageSize;         /* Total number of bytes on a page */
  u32 usableSize;       /* Number of usable bytes on each page */
63150
63151
63152
63153
63154
63155
63156

63157
63158
63159
63160
63161
63162
63163
*/
#define BTCF_WriteFlag    0x01   /* True if a write cursor */
#define BTCF_ValidNKey    0x02   /* True if info.nKey is valid */
#define BTCF_ValidOvfl    0x04   /* True if aOverflow is valid */
#define BTCF_AtLast       0x08   /* Cursor is pointing ot the last entry */
#define BTCF_Incrblob     0x10   /* True if an incremental I/O handle */
#define BTCF_Multiple     0x20   /* Maybe another cursor on the same btree */


/*
** Potential values for BtCursor.eState.
**
** CURSOR_INVALID:
**   Cursor does not point to a valid entry. This can happen (for example) 
**   because the table is empty or because BtreeCursorFirst() has not been







>







63583
63584
63585
63586
63587
63588
63589
63590
63591
63592
63593
63594
63595
63596
63597
*/
#define BTCF_WriteFlag    0x01   /* True if a write cursor */
#define BTCF_ValidNKey    0x02   /* True if info.nKey is valid */
#define BTCF_ValidOvfl    0x04   /* True if aOverflow is valid */
#define BTCF_AtLast       0x08   /* Cursor is pointing ot the last entry */
#define BTCF_Incrblob     0x10   /* True if an incremental I/O handle */
#define BTCF_Multiple     0x20   /* Maybe another cursor on the same btree */
#define BTCF_Pinned       0x40   /* Cursor is busy and cannot be moved */

/*
** Potential values for BtCursor.eState.
**
** CURSOR_INVALID:
**   Cursor does not point to a valid entry. This can happen (for example) 
**   because the table is empty or because BtreeCursorFirst() has not been
64227
64228
64229
64230
64231
64232
64233
64234
64235
64236
64237
64238
64239
64240
64241
**
** This function is called when a free-list leaf page is removed from the
** free-list for reuse. It returns false if it is safe to retrieve the
** page from the pager layer with the 'no-content' flag set. True otherwise.
*/
static int btreeGetHasContent(BtShared *pBt, Pgno pgno){
  Bitvec *p = pBt->pHasContent;
  return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno)));
}

/*
** Clear (destroy) the BtShared.pHasContent bitvec. This should be
** invoked at the conclusion of each write-transaction.
*/
static void btreeClearHasContent(BtShared *pBt){







|







64661
64662
64663
64664
64665
64666
64667
64668
64669
64670
64671
64672
64673
64674
64675
**
** This function is called when a free-list leaf page is removed from the
** free-list for reuse. It returns false if it is safe to retrieve the
** page from the pager layer with the 'no-content' flag set. True otherwise.
*/
static int btreeGetHasContent(BtShared *pBt, Pgno pgno){
  Bitvec *p = pBt->pHasContent;
  return p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTestNotNull(p, pgno));
}

/*
** Clear (destroy) the BtShared.pHasContent bitvec. This should be
** invoked at the conclusion of each write-transaction.
*/
static void btreeClearHasContent(BtShared *pBt){
64315
64316
64317
64318
64319
64320
64321



64322
64323
64324
64325
64326
64327
64328
static int saveCursorPosition(BtCursor *pCur){
  int rc;

  assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
  assert( 0==pCur->pKey );
  assert( cursorHoldsMutex(pCur) );




  if( pCur->eState==CURSOR_SKIPNEXT ){
    pCur->eState = CURSOR_VALID;
  }else{
    pCur->skipNext = 0;
  }

  rc = saveCursorKey(pCur);







>
>
>







64749
64750
64751
64752
64753
64754
64755
64756
64757
64758
64759
64760
64761
64762
64763
64764
64765
static int saveCursorPosition(BtCursor *pCur){
  int rc;

  assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
  assert( 0==pCur->pKey );
  assert( cursorHoldsMutex(pCur) );

  if( pCur->curFlags & BTCF_Pinned ){
    return SQLITE_CONSTRAINT_PINNED;
  }
  if( pCur->eState==CURSOR_SKIPNEXT ){
    pCur->eState = CURSOR_VALID;
  }else{
    pCur->skipNext = 0;
  }

  rc = saveCursorKey(pCur);
65071
65072
65073
65074
65075
65076
65077
65078
65079
65080
65081
65082
65083
65084
65085
        }
        if( iFree2 ){
          if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage);
          sz2 = get2byte(&data[iFree2+2]);
          if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
          memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
          sz += sz2;
        }else if( iFree+sz>usableSize ){
          return SQLITE_CORRUPT_PAGE(pPage);
        }

        cbrk = top+sz;
        assert( cbrk+(iFree-top) <= usableSize );
        memmove(&data[cbrk], &data[top], iFree-top);
        for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){







|







65508
65509
65510
65511
65512
65513
65514
65515
65516
65517
65518
65519
65520
65521
65522
        }
        if( iFree2 ){
          if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage);
          sz2 = get2byte(&data[iFree2+2]);
          if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
          memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
          sz += sz2;
        }else if( NEVER(iFree+sz>usableSize) ){
          return SQLITE_CORRUPT_PAGE(pPage);
        }

        cbrk = top+sz;
        assert( cbrk+(iFree-top) <= usableSize );
        memmove(&data[cbrk], &data[top], iFree-top);
        for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){
65263
65264
65265
65266
65267
65268
65269

65270
65271

65272
65273
65274
65275
65276
65277
65278
  */
  testcase( gap+2==top );
  testcase( gap+1==top );
  testcase( gap==top );
  if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){
    u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
    if( pSpace ){

      assert( pSpace+nByte<=data+pPage->pBt->usableSize );
      if( (*pIdx = (int)(pSpace-data))<=gap ){

        return SQLITE_CORRUPT_PAGE(pPage);
      }else{
        return SQLITE_OK;
      }
    }else if( rc ){
      return rc;
    }







>

|
>







65700
65701
65702
65703
65704
65705
65706
65707
65708
65709
65710
65711
65712
65713
65714
65715
65716
65717
  */
  testcase( gap+2==top );
  testcase( gap+1==top );
  testcase( gap==top );
  if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){
    u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
    if( pSpace ){
      int g2;
      assert( pSpace+nByte<=data+pPage->pBt->usableSize );
      *pIdx = g2 = (int)(pSpace-data);
      if( NEVER(g2<=gap) ){
        return SQLITE_CORRUPT_PAGE(pPage);
      }else{
        return SQLITE_OK;
      }
    }else if( rc ){
      return rc;
    }
65342
65343
65344
65345
65346
65347
65348
65349
65350
65351
65352
65353
65354
65355
65356
65357
65358
65359
65360
65361
65362
65363
65364
65365
65366
65367
65368
65369
65370
65371
65372
65373
65374
65375
65376
  hdr = pPage->hdrOffset;
  iPtr = hdr + 1;
  if( data[iPtr+1]==0 && data[iPtr]==0 ){
    iFreeBlk = 0;  /* Shortcut for the case when the freelist is empty */
  }else{
    while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
      if( iFreeBlk<iPtr+4 ){
        if( iFreeBlk==0 ) break;
        return SQLITE_CORRUPT_PAGE(pPage);
      }
      iPtr = iFreeBlk;
    }
    if( iFreeBlk>pPage->pBt->usableSize-4 ){
      return SQLITE_CORRUPT_PAGE(pPage);
    }
    assert( iFreeBlk>iPtr || iFreeBlk==0 );
  
    /* At this point:
    **    iFreeBlk:   First freeblock after iStart, or zero if none
    **    iPtr:       The address of a pointer to iFreeBlk
    **
    ** Check to see if iFreeBlk should be coalesced onto the end of iStart.
    */
    if( iFreeBlk && iEnd+3>=iFreeBlk ){
      nFrag = iFreeBlk - iEnd;
      if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
      iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
      if( iEnd > pPage->pBt->usableSize ){
        return SQLITE_CORRUPT_PAGE(pPage);
      }
      iSize = iEnd - iStart;
      iFreeBlk = get2byte(&data[iFreeBlk]);
    }
  
    /* If iPtr is another freeblock (that is, if iPtr is not the freelist







|




|














|







65781
65782
65783
65784
65785
65786
65787
65788
65789
65790
65791
65792
65793
65794
65795
65796
65797
65798
65799
65800
65801
65802
65803
65804
65805
65806
65807
65808
65809
65810
65811
65812
65813
65814
65815
  hdr = pPage->hdrOffset;
  iPtr = hdr + 1;
  if( data[iPtr+1]==0 && data[iPtr]==0 ){
    iFreeBlk = 0;  /* Shortcut for the case when the freelist is empty */
  }else{
    while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
      if( iFreeBlk<iPtr+4 ){
        if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
        return SQLITE_CORRUPT_PAGE(pPage);
      }
      iPtr = iFreeBlk;
    }
    if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
      return SQLITE_CORRUPT_PAGE(pPage);
    }
    assert( iFreeBlk>iPtr || iFreeBlk==0 );
  
    /* At this point:
    **    iFreeBlk:   First freeblock after iStart, or zero if none
    **    iPtr:       The address of a pointer to iFreeBlk
    **
    ** Check to see if iFreeBlk should be coalesced onto the end of iStart.
    */
    if( iFreeBlk && iEnd+3>=iFreeBlk ){
      nFrag = iFreeBlk - iEnd;
      if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
      iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
      if( NEVER(iEnd > pPage->pBt->usableSize) ){
        return SQLITE_CORRUPT_PAGE(pPage);
      }
      iSize = iEnd - iStart;
      iFreeBlk = get2byte(&data[iFreeBlk]);
    }
  
    /* If iPtr is another freeblock (that is, if iPtr is not the freelist
65390
65391
65392
65393
65394
65395
65396

65397
65398
65399
65400
65401
65402
65403
65404
    data[hdr+7] -= nFrag;
  }
  x = get2byte(&data[hdr+5]);
  if( iStart<=x ){
    /* The new freeblock is at the beginning of the cell content area,
    ** so just extend the cell content area rather than create another
    ** freelist entry */

    if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
    put2byte(&data[hdr+1], iFreeBlk);
    put2byte(&data[hdr+5], iEnd);
  }else{
    /* Insert the new freeblock into the freelist */
    put2byte(&data[iPtr], iStart);
  }
  if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){







>
|







65829
65830
65831
65832
65833
65834
65835
65836
65837
65838
65839
65840
65841
65842
65843
65844
    data[hdr+7] -= nFrag;
  }
  x = get2byte(&data[hdr+5]);
  if( iStart<=x ){
    /* The new freeblock is at the beginning of the cell content area,
    ** so just extend the cell content area rather than create another
    ** freelist entry */
    if( iStart<x ) return SQLITE_CORRUPT_PAGE(pPage);
    if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
    put2byte(&data[hdr+1], iFreeBlk);
    put2byte(&data[hdr+5], iEnd);
  }else{
    /* Insert the new freeblock into the freelist */
    put2byte(&data[iPtr], iStart);
  }
  if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
65510
65511
65512
65513
65514
65515
65516
65517
65518
65519
65520
65521
65522
65523
65524
  ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
  ** start of the first freeblock on the page, or is zero if there are no
  ** freeblocks. */
  pc = get2byte(&data[hdr+1]);
  nFree = data[hdr+7] + top;  /* Init nFree to non-freeblock free space */
  if( pc>0 ){
    u32 next, size;
    if( pc<iCellFirst ){
      /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
      ** always be at least one cell before the first freeblock.
      */
      return SQLITE_CORRUPT_PAGE(pPage); 
    }
    while( 1 ){
      if( pc>iCellLast ){







|







65950
65951
65952
65953
65954
65955
65956
65957
65958
65959
65960
65961
65962
65963
65964
  ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
  ** start of the first freeblock on the page, or is zero if there are no
  ** freeblocks. */
  pc = get2byte(&data[hdr+1]);
  nFree = data[hdr+7] + top;  /* Init nFree to non-freeblock free space */
  if( pc>0 ){
    u32 next, size;
    if( pc<top ){
      /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
      ** always be at least one cell before the first freeblock.
      */
      return SQLITE_CORRUPT_PAGE(pPage); 
    }
    while( 1 ){
      if( pc>iCellLast ){
65747
65748
65749
65750
65751
65752
65753

65754
65755
65756
65757
65758
65759
65760
65761
65762
65763
65764
65765
65766
}

/*
** Return the size of the database file in pages. If there is any kind of
** error, return ((unsigned int)-1).
*/
static Pgno btreePagecount(BtShared *pBt){

  return pBt->nPage;
}
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
  assert( sqlite3BtreeHoldsMutex(p) );
  assert( ((p->pBt->nPage)&0x80000000)==0 );
  return btreePagecount(p->pBt);
}

/*
** Get a page from the pager and initialize it.
**
** If pCur!=0 then the page is being fetched as part of a moveToChild()
** call.  Do additional sanity checking on the page in this case.







>




<
|







66187
66188
66189
66190
66191
66192
66193
66194
66195
66196
66197
66198

66199
66200
66201
66202
66203
66204
66205
66206
}

/*
** Return the size of the database file in pages. If there is any kind of
** error, return ((unsigned int)-1).
*/
static Pgno btreePagecount(BtShared *pBt){
  assert( (pBt->nPage & 0x80000000)==0 || CORRUPT_DB );
  return pBt->nPage;
}
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
  assert( sqlite3BtreeHoldsMutex(p) );

  return btreePagecount(p->pBt) & 0x7fffffff;
}

/*
** Get a page from the pager and initialize it.
**
** If pCur!=0 then the page is being fetched as part of a moveToChild()
** call.  Do additional sanity checking on the page in this case.
66019
66020
66021
66022
66023
66024
66025



66026
66027
66028

66029
66030
66031
66032
66033
66034
66035
      }
      if( isMemdb ){
        memcpy(zFullPathname, zFilename, nFilename);
      }else{
        rc = sqlite3OsFullPathname(pVfs, zFilename,
                                   nFullPathname, zFullPathname);
        if( rc ){



          sqlite3_free(zFullPathname);
          sqlite3_free(p);
          return rc;

        }
      }
#if SQLITE_THREADSAFE
      mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
      sqlite3_mutex_enter(mutexOpen);
      mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
      sqlite3_mutex_enter(mutexShared);







>
>
>
|
|
|
>







66459
66460
66461
66462
66463
66464
66465
66466
66467
66468
66469
66470
66471
66472
66473
66474
66475
66476
66477
66478
66479
      }
      if( isMemdb ){
        memcpy(zFullPathname, zFilename, nFilename);
      }else{
        rc = sqlite3OsFullPathname(pVfs, zFilename,
                                   nFullPathname, zFullPathname);
        if( rc ){
          if( rc==SQLITE_OK_SYMLINK ){
            rc = SQLITE_OK;
          }else{
            sqlite3_free(zFullPathname);
            sqlite3_free(p);
            return rc;
          }
        }
      }
#if SQLITE_THREADSAFE
      mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
      sqlite3_mutex_enter(mutexOpen);
      mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
      sqlite3_mutex_enter(mutexShared);
66463
66464
66465
66466
66467
66468
66469
66470
66471
66472
66473
66474


66475
66476
66477
66478
66479
66480
66481
**
** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
** and autovacuum mode can no longer be changed.
*/
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
  int rc = SQLITE_OK;
  BtShared *pBt = p->pBt;
  assert( nReserve>=-1 && nReserve<=255 );
  sqlite3BtreeEnter(p);
#if SQLITE_HAS_CODEC
  if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve;
#endif


  if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
    sqlite3BtreeLeave(p);
    return SQLITE_READONLY;
  }
  if( nReserve<0 ){
    nReserve = pBt->pageSize - pBt->usableSize;
  }







|

<
|
<
>
>







66907
66908
66909
66910
66911
66912
66913
66914
66915

66916

66917
66918
66919
66920
66921
66922
66923
66924
66925
**
** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
** and autovacuum mode can no longer be changed.
*/
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
  int rc = SQLITE_OK;
  BtShared *pBt = p->pBt;
  assert( nReserve>=-1 && nReserve<=254 );
  sqlite3BtreeEnter(p);

  if( nReserve>=0 ){

    pBt->nReserveWanted = nReserve + 1;
  }
  if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
    sqlite3BtreeLeave(p);
    return SQLITE_READONLY;
  }
  if( nReserve<0 ){
    nReserve = pBt->pageSize - pBt->usableSize;
  }
66519
66520
66521
66522
66523
66524
66525
66526
66527
66528
66529
66530
66531
66532
66533

66534
66535
66536
66537
66538
66539
66540
66541
66542
66543
66544
  return n;
}

/*
** Return the number of bytes of space at the end of every page that
** are intentually left unused.  This is the "reserved" space that is
** sometimes used by extensions.
**
** If SQLITE_HAS_MUTEX is defined then the number returned is the
** greater of the current reserved space and the maximum requested
** reserve space.
*/
SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){
  int n;
  sqlite3BtreeEnter(p);

  n = sqlite3BtreeGetReserveNoMutex(p);
#ifdef SQLITE_HAS_CODEC
  if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve;
#endif
  sqlite3BtreeLeave(p);
  return n;
}


/*
** Set the maximum page count for a database if mxPage is positive.







<
<
<
<

|


>
|
<
<
<







66963
66964
66965
66966
66967
66968
66969




66970
66971
66972
66973
66974
66975



66976
66977
66978
66979
66980
66981
66982
  return n;
}

/*
** Return the number of bytes of space at the end of every page that
** are intentually left unused.  This is the "reserved" space that is
** sometimes used by extensions.




*/
SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){
  int n;
  sqlite3BtreeEnter(p);
  n = ((int)p->pBt->nReserveWanted) - 1;
  if( n<0 ) n = sqlite3BtreeGetReserveNoMutex(p);



  sqlite3BtreeLeave(p);
  return n;
}


/*
** Set the maximum page count for a database if mxPage is positive.
68173
68174
68175
68176
68177
68178
68179












68180
68181
68182
68183
68184
68185
68186
SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
  assert( cursorHoldsMutex(pCur) );
  assert( pCur->eState==CURSOR_VALID );
  assert( pCur->curIntKey );
  getCellInfo(pCur);
  return pCur->info.nKey;
}













#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
/*
** Return the offset into the database file for the start of the
** payload to which the cursor is pointing.
*/
SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){







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







68611
68612
68613
68614
68615
68616
68617
68618
68619
68620
68621
68622
68623
68624
68625
68626
68627
68628
68629
68630
68631
68632
68633
68634
68635
68636
SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
  assert( cursorHoldsMutex(pCur) );
  assert( pCur->eState==CURSOR_VALID );
  assert( pCur->curIntKey );
  getCellInfo(pCur);
  return pCur->info.nKey;
}

/*
** Pin or unpin a cursor.
*/
SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor *pCur){
  assert( (pCur->curFlags & BTCF_Pinned)==0 );
  pCur->curFlags |= BTCF_Pinned;
}
SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor *pCur){
  assert( (pCur->curFlags & BTCF_Pinned)!=0 );
  pCur->curFlags &= ~BTCF_Pinned;
}

#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
/*
** Return the offset into the database file for the start of the
** payload to which the cursor is pointing.
*/
SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){
69330
69331
69332
69333
69334
69335
69336
69337



69338
69339
69340
69341
69342
69343
69344
69345
    return SQLITE_CORRUPT_BKPT;
  }

  /* If the database file is corrupt, it is possible for the value of idx 
  ** to be invalid here. This can only occur if a second cursor modifies
  ** the page while cursor pCur is holding a reference to it. Which can
  ** only happen if the database is corrupt in such a way as to link the
  ** page into more than one b-tree structure. */



  testcase( idx>pPage->nCell );

  if( idx>=pPage->nCell ){
    if( !pPage->leaf ){
      rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
      if( rc ) return rc;
      return moveToLeftmost(pCur);
    }







|
>
>
>
|







69780
69781
69782
69783
69784
69785
69786
69787
69788
69789
69790
69791
69792
69793
69794
69795
69796
69797
69798
    return SQLITE_CORRUPT_BKPT;
  }

  /* If the database file is corrupt, it is possible for the value of idx 
  ** to be invalid here. This can only occur if a second cursor modifies
  ** the page while cursor pCur is holding a reference to it. Which can
  ** only happen if the database is corrupt in such a way as to link the
  ** page into more than one b-tree structure.
  **
  ** Update 2019-12-23: appears to long longer be possible after the
  ** addition of anotherValidCursor() condition on balance_deeper().  */
  harmless( idx>pPage->nCell );

  if( idx>=pPage->nCell ){
    if( !pPage->leaf ){
      rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
      if( rc ) return rc;
      return moveToLeftmost(pCur);
    }
70530
70531
70532
70533
70534
70535
70536
70537
70538
70539
70540
70541
70542
70543
70544
  u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
  u8 *pData;
  int k;                          /* Current slot in pCArray->apEnd[] */
  u8 *pSrcEnd;                    /* Current pCArray->apEnd[k] value */

  assert( i<iEnd );
  j = get2byte(&aData[hdr+5]);
  if( j>(u32)usableSize ){ j = 0; }
  memcpy(&pTmp[j], &aData[j], usableSize - j);

  for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
  pSrcEnd = pCArray->apEnd[k];

  pData = pEnd;
  while( 1/*exit by break*/ ){







|







70983
70984
70985
70986
70987
70988
70989
70990
70991
70992
70993
70994
70995
70996
70997
  u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
  u8 *pData;
  int k;                          /* Current slot in pCArray->apEnd[] */
  u8 *pSrcEnd;                    /* Current pCArray->apEnd[k] value */

  assert( i<iEnd );
  j = get2byte(&aData[hdr+5]);
  if( NEVER(j>(u32)usableSize) ){ j = 0; }
  memcpy(&pTmp[j], &aData[j], usableSize - j);

  for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
  pSrcEnd = pCArray->apEnd[k];

  pData = pEnd;
  while( 1/*exit by break*/ ){
70556
70557
70558
70559
70560
70561
70562
70563
70564
70565
70566
70567
70568
70569
70570

    pData -= sz;
    put2byte(pCellptr, (pData - aData));
    pCellptr += 2;
    if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
    memcpy(pData, pCell, sz);
    assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
    testcase( sz!=pPg->xCellSize(pPg,pCell) );
    i++;
    if( i>=iEnd ) break;
    if( pCArray->ixNx[k]<=i ){
      k++;
      pSrcEnd = pCArray->apEnd[k];
    }
  }







|







71009
71010
71011
71012
71013
71014
71015
71016
71017
71018
71019
71020
71021
71022
71023

    pData -= sz;
    put2byte(pCellptr, (pData - aData));
    pCellptr += 2;
    if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
    memcpy(pData, pCell, sz);
    assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
    testcase( sz!=pPg->xCellSize(pPg,pCell) )
    i++;
    if( i>=iEnd ) break;
    if( pCArray->ixNx[k]<=i ){
      k++;
      pSrcEnd = pCArray->apEnd[k];
    }
  }
71919
71920
71921
71922
71923
71924
71925
























71926
71927
71928
71929
71930
71931
71932
  /* Zero the contents of pRoot. Then install pChild as the right-child. */
  zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF);
  put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild);

  *ppChild = pChild;
  return SQLITE_OK;
}

























/*
** The page that pCur currently points to has just been modified in
** some way. This function figures out if this modification means the
** tree needs to be balanced, and if so calls the appropriate balancing 
** routine. Balancing routines are:
**







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







72372
72373
72374
72375
72376
72377
72378
72379
72380
72381
72382
72383
72384
72385
72386
72387
72388
72389
72390
72391
72392
72393
72394
72395
72396
72397
72398
72399
72400
72401
72402
72403
72404
72405
72406
72407
72408
72409
  /* Zero the contents of pRoot. Then install pChild as the right-child. */
  zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF);
  put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild);

  *ppChild = pChild;
  return SQLITE_OK;
}

/*
** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
** on the same B-tree as pCur.
**
** This can if a database is corrupt with two or more SQL tables
** pointing to the same b-tree.  If an insert occurs on one SQL table
** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
** table linked to the same b-tree.  If the secondary insert causes a
** rebalance, that can change content out from under the cursor on the
** first SQL table, violating invariants on the first insert.
*/
static int anotherValidCursor(BtCursor *pCur){
  BtCursor *pOther;
  for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){
    if( pOther!=pCur
     && pOther->eState==CURSOR_VALID
     && pOther->pPage==pCur->pPage
    ){
      return SQLITE_CORRUPT_BKPT;
    }
  }
  return SQLITE_OK;
}

/*
** The page that pCur currently points to has just been modified in
** some way. This function figures out if this modification means the
** tree needs to be balanced, and if so calls the appropriate balancing 
** routine. Balancing routines are:
**
71947
71948
71949
71950
71951
71952
71953
71954
71955
71956
71957
71958
71959
71960
71961
    int iPage;
    MemPage *pPage = pCur->pPage;

    if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break;
    if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
      break;
    }else if( (iPage = pCur->iPage)==0 ){
      if( pPage->nOverflow ){
        /* The root page of the b-tree is overfull. In this case call the
        ** balance_deeper() function to create a new child for the root-page
        ** and copy the current contents of the root-page to it. The
        ** next iteration of the do-loop will balance the child page.
        */ 
        assert( balance_deeper_called==0 );
        VVA_ONLY( balance_deeper_called++ );







|







72424
72425
72426
72427
72428
72429
72430
72431
72432
72433
72434
72435
72436
72437
72438
    int iPage;
    MemPage *pPage = pCur->pPage;

    if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break;
    if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
      break;
    }else if( (iPage = pCur->iPage)==0 ){
      if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){
        /* The root page of the b-tree is overfull. In this case call the
        ** balance_deeper() function to create a new child for the root-page
        ** and copy the current contents of the root-page to it. The
        ** next iteration of the do-loop will balance the child page.
        */ 
        assert( balance_deeper_called==0 );
        VVA_ONLY( balance_deeper_called++ );
72243
72244
72245
72246
72247
72248
72249
72250
72251
72252
72253
72254
72255
72256
72257
    /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing 
    ** to a row with the same key as the new entry being inserted.
    */
#ifdef SQLITE_DEBUG
    if( flags & BTREE_SAVEPOSITION ){
      assert( pCur->curFlags & BTCF_ValidNKey );
      assert( pX->nKey==pCur->info.nKey );
      assert( pCur->info.nSize!=0 );
      assert( loc==0 );
    }
#endif

    /* On the other hand, BTREE_SAVEPOSITION==0 does not imply
    ** that the cursor is not pointing to a row to be overwritten.
    ** So do a complete check.







<







72720
72721
72722
72723
72724
72725
72726

72727
72728
72729
72730
72731
72732
72733
    /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing 
    ** to a row with the same key as the new entry being inserted.
    */
#ifdef SQLITE_DEBUG
    if( flags & BTREE_SAVEPOSITION ){
      assert( pCur->curFlags & BTCF_ValidNKey );
      assert( pX->nKey==pCur->info.nKey );

      assert( loc==0 );
    }
#endif

    /* On the other hand, BTREE_SAVEPOSITION==0 does not imply
    ** that the cursor is not pointing to a row to be overwritten.
    ** So do a complete check.
72318
72319
72320
72321
72322
72323
72324
72325


72326
72327
72328
72329
72330
72331
72332
        x2.nData = pX->nKey;
        x2.nZero = 0;
        return btreeOverwriteCell(pCur, &x2);
      }
    }

  }
  assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );



  pPage = pCur->pPage;
  assert( pPage->intKey || pX->nKey>=0 );
  assert( pPage->leaf || !pPage->intKey );
  if( pPage->nFree<0 ){
    rc = btreeComputeFreeSpace(pPage);
    if( rc ) return rc;







|
>
>







72794
72795
72796
72797
72798
72799
72800
72801
72802
72803
72804
72805
72806
72807
72808
72809
72810
        x2.nData = pX->nKey;
        x2.nZero = 0;
        return btreeOverwriteCell(pCur, &x2);
      }
    }

  }
  assert( pCur->eState==CURSOR_VALID 
       || (pCur->eState==CURSOR_INVALID && loc)
       || CORRUPT_DB );

  pPage = pCur->pPage;
  assert( pPage->intKey || pX->nKey>=0 );
  assert( pPage->leaf || !pPage->intKey );
  if( pPage->nFree<0 ){
    rc = btreeComputeFreeSpace(pPage);
    if( rc ) return rc;
73102
73103
73104
73105
73106
73107
73108
73109
73110
73111
73112
73113
73114
73115
73116
    *pnEntry = 0;
    return SQLITE_OK;
  }

  /* Unless an error occurs, the following loop runs one iteration for each
  ** page in the B-Tree structure (not including overflow pages). 
  */
  while( rc==SQLITE_OK && !db->u1.isInterrupted ){
    int iIdx;                          /* Index of child node in parent */
    MemPage *pPage;                    /* Current page of the b-tree */

    /* If this is a leaf page or the tree is not an int-key tree, then 
    ** this page contains countable entries. Increment the entry counter
    ** accordingly.
    */







|







73580
73581
73582
73583
73584
73585
73586
73587
73588
73589
73590
73591
73592
73593
73594
    *pnEntry = 0;
    return SQLITE_OK;
  }

  /* Unless an error occurs, the following loop runs one iteration for each
  ** page in the B-Tree structure (not including overflow pages). 
  */
  while( rc==SQLITE_OK && !AtomicLoad(&db->u1.isInterrupted) ){
    int iIdx;                          /* Index of child node in parent */
    MemPage *pPage;                    /* Current page of the b-tree */

    /* If this is a leaf page or the tree is not an int-key tree, then 
    ** this page contains countable entries. Increment the entry counter
    ** accordingly.
    */
73228
73229
73230
73231
73232
73233
73234
73235
73236
73237
73238
73239
73240
73241
73242
    checkAppendMsg(pCheck, "invalid page number %d", iPage);
    return 1;
  }
  if( getPageReferenced(pCheck, iPage) ){
    checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
    return 1;
  }
  if( pCheck->db->u1.isInterrupted ) return 1;
  setPageReferenced(pCheck, iPage);
  return 0;
}

#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Check that the entry in the pointer-map for page iChild maps to 







|







73706
73707
73708
73709
73710
73711
73712
73713
73714
73715
73716
73717
73718
73719
73720
    checkAppendMsg(pCheck, "invalid page number %d", iPage);
    return 1;
  }
  if( getPageReferenced(pCheck, iPage) ){
    checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
    return 1;
  }
  if( AtomicLoad(&pCheck->db->u1.isInterrupted) ) return 1;
  setPageReferenced(pCheck, iPage);
  return 0;
}

#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Check that the entry in the pointer-map for page iChild maps to 
74327
74328
74329
74330
74331
74332
74333
74334
74335
74336
74337
74338
74339
74340
74341
74342
74343
74344
74345
74346
74347
74348
74349
74350
74351
74352
74353
74354
74355
74356
74357
74358
74359
74360
74361
74362
74363
74364
74365
74366
74367
74368
74369
74370
74371
74372
74373
74374
74375
74376
74377
74378
74379
74380
74381
74382
74383
  int bUpdate                     /* True for an update, false otherwise */
){
  Pager * const pDestPager = sqlite3BtreePager(p->pDest);
  const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc);
  int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
  const int nCopy = MIN(nSrcPgsz, nDestPgsz);
  const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
#ifdef SQLITE_HAS_CODEC
  /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is
  ** guaranteed that the shared-mutex is held by this thread, handle
  ** p->pSrc may not actually be the owner.  */
  int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
  int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest);
#endif
  int rc = SQLITE_OK;
  i64 iOff;

  assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 );
  assert( p->bDestLocked );
  assert( !isFatalError(p->rc) );
  assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
  assert( zSrcData );

  /* Catch the case where the destination is an in-memory database and the
  ** page sizes of the source and destination differ. 
  */
  if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
    rc = SQLITE_READONLY;
  }

#ifdef SQLITE_HAS_CODEC
  /* Backup is not possible if the page size of the destination is changing
  ** and a codec is in use.
  */
  if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){
    rc = SQLITE_READONLY;
  }

  /* Backup is not possible if the number of bytes of reserve space differ
  ** between source and destination.  If there is a difference, try to
  ** fix the destination to agree with the source.  If that is not possible,
  ** then the backup cannot proceed.
  */
  if( nSrcReserve!=nDestReserve ){
    u32 newPgsz = nSrcPgsz;
    rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve);
    if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY;
  }
#endif

  /* This loop runs once for each destination page spanned by the source 
  ** page. For each iteration, variable iOff is set to the byte offset
  ** of the destination page.
  */
  for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){
    DbPage *pDestPg = 0;
    Pgno iDest = (Pgno)(iOff/nDestPgsz)+1;







<
<
<
<
<
<
<
















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







74805
74806
74807
74808
74809
74810
74811







74812
74813
74814
74815
74816
74817
74818
74819
74820
74821
74822
74823
74824
74825
74826
74827




















74828
74829
74830
74831
74832
74833
74834
  int bUpdate                     /* True for an update, false otherwise */
){
  Pager * const pDestPager = sqlite3BtreePager(p->pDest);
  const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc);
  int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
  const int nCopy = MIN(nSrcPgsz, nDestPgsz);
  const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;







  int rc = SQLITE_OK;
  i64 iOff;

  assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 );
  assert( p->bDestLocked );
  assert( !isFatalError(p->rc) );
  assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
  assert( zSrcData );

  /* Catch the case where the destination is an in-memory database and the
  ** page sizes of the source and destination differ. 
  */
  if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
    rc = SQLITE_READONLY;
  }





















  /* This loop runs once for each destination page spanned by the source 
  ** page. For each iteration, variable iOff is set to the byte offset
  ** of the destination page.
  */
  for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){
    DbPage *pDestPg = 0;
    Pgno iDest = (Pgno)(iOff/nDestPgsz)+1;
74865
74866
74867
74868
74869
74870
74871
74872
74873
74874
74875
74876
74877
74878
74879
74880
74881
74882
  */
  memset(&b, 0, sizeof(b));
  b.pSrcDb = pFrom->db;
  b.pSrc = pFrom;
  b.pDest = pTo;
  b.iNext = 1;

#ifdef SQLITE_HAS_CODEC
  sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom));
#endif

  /* 0x7FFFFFFF is the hard limit for the number of pages in a database
  ** file. By passing this as the number of pages to copy to
  ** sqlite3_backup_step(), we can guarantee that the copy finishes 
  ** within a single call (unless an error occurs). The assert() statement
  ** checks this assumption - (p->rc) should be set to either SQLITE_DONE 
  ** or an error code.  */
  sqlite3_backup_step(&b, 0x7FFFFFFF);







<
<
<
<







75316
75317
75318
75319
75320
75321
75322




75323
75324
75325
75326
75327
75328
75329
  */
  memset(&b, 0, sizeof(b));
  b.pSrcDb = pFrom->db;
  b.pSrc = pFrom;
  b.pDest = pTo;
  b.iNext = 1;





  /* 0x7FFFFFFF is the hard limit for the number of pages in a database
  ** file. By passing this as the number of pages to copy to
  ** sqlite3_backup_step(), we can guarantee that the copy finishes 
  ** within a single call (unless an error occurs). The assert() statement
  ** checks this assumption - (p->rc) should be set to either SQLITE_DONE 
  ** or an error code.  */
  sqlite3_backup_step(&b, 0x7FFFFFFF);
75487
75488
75489
75490
75491
75492
75493
75494
75495
75496
75497
75498
75499
75500
75501
75502
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );
  flags = pMem->flags;
  if( flags & (MEM_Int|MEM_IntReal) ){
    testcase( flags & MEM_IntReal );
    return pMem->u.i;
  }else if( flags & MEM_Real ){
    return doubleToInt64(pMem->u.r);
  }else if( flags & (MEM_Str|MEM_Blob) ){
    assert( pMem->z || pMem->n==0 );
    return memIntValue(pMem);
  }else{
    return 0;
  }
}

/*







|
<







75934
75935
75936
75937
75938
75939
75940
75941

75942
75943
75944
75945
75946
75947
75948
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );
  flags = pMem->flags;
  if( flags & (MEM_Int|MEM_IntReal) ){
    testcase( flags & MEM_IntReal );
    return pMem->u.i;
  }else if( flags & MEM_Real ){
    return doubleToInt64(pMem->u.r);
  }else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){

    return memIntValue(pMem);
  }else{
    return 0;
  }
}

/*
75645
75646
75647
75648
75649
75650
75651
75652
75653
75654
75655
75656
75657
75658
75659
75660
/*
** Cast the datatype of the value in pMem according to the affinity
** "aff".  Casting is different from applying affinity in that a cast
** is forced.  In other words, the value is converted into the desired
** affinity even if that results in loss of data.  This routine is
** used (for example) to implement the SQL "cast()" operator.
*/
SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
  if( pMem->flags & MEM_Null ) return;
  switch( aff ){
    case SQLITE_AFF_BLOB: {   /* Really a cast to BLOB */
      if( (pMem->flags & MEM_Blob)==0 ){
        sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
        assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
        if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob);
      }else{







|
|







76091
76092
76093
76094
76095
76096
76097
76098
76099
76100
76101
76102
76103
76104
76105
76106
/*
** Cast the datatype of the value in pMem according to the affinity
** "aff".  Casting is different from applying affinity in that a cast
** is forced.  In other words, the value is converted into the desired
** affinity even if that results in loss of data.  This routine is
** used (for example) to implement the SQL "cast()" operator.
*/
SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
  if( pMem->flags & MEM_Null ) return SQLITE_OK;
  switch( aff ){
    case SQLITE_AFF_BLOB: {   /* Really a cast to BLOB */
      if( (pMem->flags & MEM_Blob)==0 ){
        sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
        assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
        if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob);
      }else{
75677
75678
75679
75680
75681
75682
75683
75684
75685
75686

75687
75688
75689
75690
75691
75692
75693
    default: {
      assert( aff==SQLITE_AFF_TEXT );
      assert( MEM_Str==(MEM_Blob>>3) );
      pMem->flags |= (pMem->flags&MEM_Blob)>>3;
      sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
      assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
      pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
      break;
    }
  }

}

/*
** Initialize bulk memory to be a consistent Mem object.
**
** The minimum amount of initialization feasible is performed.
*/







|


>







76123
76124
76125
76126
76127
76128
76129
76130
76131
76132
76133
76134
76135
76136
76137
76138
76139
76140
    default: {
      assert( aff==SQLITE_AFF_TEXT );
      assert( MEM_Str==(MEM_Blob>>3) );
      pMem->flags |= (pMem->flags&MEM_Blob)>>3;
      sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
      assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
      pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
      return sqlite3VdbeChangeEncoding(pMem, encoding);
    }
  }
  return SQLITE_OK;
}

/*
** Initialize bulk memory to be a consistent Mem object.
**
** The minimum amount of initialization feasible is performed.
*/
75845
75846
75847
75848
75849
75850
75851
75852
75853
75854
75855
75856
75857
75858
75859





75860
75861
75862
75863
75864
75865
75866
75867
75868
75869
75870
75871
75872
75873
75874
75875
75876
75877
75878
75879
75880
75881
75882
75883
75884
75885
75886
75887
75888

#ifdef SQLITE_DEBUG
/*
** This routine prepares a memory cell for modification by breaking
** its link to a shallow copy and by marking any current shallow
** copies of this cell as invalid.
**
** This is used for testing and debugging only - to make sure shallow
** copies are not misused.
*/
SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
  int i;
  Mem *pX;
  for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
    if( pX->pScopyFrom==pMem ){





      /* If pX is marked as a shallow copy of pMem, then verify that
      ** no significant changes have been made to pX since the OP_SCopy.
      ** A significant change would indicated a missed call to this
      ** function for pX.  Minor changes, such as adding or removing a
      ** dual type, are allowed, as long as the underlying value is the
      ** same. */
      u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
      assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i );
      assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r );
      assert( (mFlags&MEM_Str)==0  || (pMem->n==pX->n && pMem->z==pX->z) );
      assert( (mFlags&MEM_Blob)==0  || sqlite3BlobCompare(pMem,pX)==0 );
      
      /* pMem is the register that is changing.  But also mark pX as
      ** undefined so that we can quickly detect the shallow-copy error */
      pX->flags = MEM_Undefined;
      pX->pScopyFrom = 0;
    }
  }
  pMem->pScopyFrom = 0;
}
#endif /* SQLITE_DEBUG */


/*
** Make an shallow copy of pFrom into pTo.  Prior contents of
** pTo are freed.  The pFrom->z field is not duplicated.  If
** pFrom->z is used, then pTo->z points to the same thing as pFrom->z
** and flags gets srcType (either MEM_Ephem or MEM_Static).
*/







|
|




|

>
>
>
>
>
|





|

<
<
<










<







76292
76293
76294
76295
76296
76297
76298
76299
76300
76301
76302
76303
76304
76305
76306
76307
76308
76309
76310
76311
76312
76313
76314
76315
76316
76317
76318
76319



76320
76321
76322
76323
76324
76325
76326
76327
76328
76329

76330
76331
76332
76333
76334
76335
76336

#ifdef SQLITE_DEBUG
/*
** This routine prepares a memory cell for modification by breaking
** its link to a shallow copy and by marking any current shallow
** copies of this cell as invalid.
**
** This is used for testing and debugging only - to help ensure that shallow
** copies (created by OP_SCopy) are not misused.
*/
SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
  int i;
  Mem *pX;
  for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){
    if( pX->pScopyFrom==pMem ){
      u16 mFlags;
      if( pVdbe->db->flags & SQLITE_VdbeTrace ){
        sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n",
          (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem));
      }
      /* If pX is marked as a shallow copy of pMem, then try to verify that
      ** no significant changes have been made to pX since the OP_SCopy.
      ** A significant change would indicated a missed call to this
      ** function for pX.  Minor changes, such as adding or removing a
      ** dual type, are allowed, as long as the underlying value is the
      ** same. */
      mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
      assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i );



      
      /* pMem is the register that is changing.  But also mark pX as
      ** undefined so that we can quickly detect the shallow-copy error */
      pX->flags = MEM_Undefined;
      pX->pScopyFrom = 0;
    }
  }
  pMem->pScopyFrom = 0;
}
#endif /* SQLITE_DEBUG */


/*
** Make an shallow copy of pFrom into pTo.  Prior contents of
** pTo are freed.  The pFrom->z field is not duplicated.  If
** pFrom->z is used, then pTo->z points to the same thing as pFrom->z
** and flags gets srcType (either MEM_Ephem or MEM_Static).
*/
76021
76022
76023
76024
76025
76026
76027

76028







76029

76030
76031
76032
76033
76034
76035
76036
76037
76038
      pMem->xDel = xDel;
      flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn);
    }
  }

  pMem->n = nByte;
  pMem->flags = flags;

  pMem->enc = (enc==0 ? SQLITE_UTF8 : enc);









#ifndef SQLITE_OMIT_UTF16
  if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
    return SQLITE_NOMEM_BKPT;
  }
#endif

  if( nByte>iLimit ){
    return SQLITE_TOOBIG;
  }







>
|
>
>
>
>
>
>
>
|
>

|







76469
76470
76471
76472
76473
76474
76475
76476
76477
76478
76479
76480
76481
76482
76483
76484
76485
76486
76487
76488
76489
76490
76491
76492
76493
76494
76495
      pMem->xDel = xDel;
      flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn);
    }
  }

  pMem->n = nByte;
  pMem->flags = flags;
  if( enc ){
    pMem->enc = enc;
#ifdef SQLITE_ENABLE_SESSION
  }else if( pMem->db==0 ){
    pMem->enc = SQLITE_UTF8;
#endif
  }else{
    assert( pMem->db!=0 );
    pMem->enc = ENC(pMem->db);
  }

#ifndef SQLITE_OMIT_UTF16
  if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
    return SQLITE_NOMEM_BKPT;
  }
#endif

  if( nByte>iLimit ){
    return SQLITE_TOOBIG;
  }
76051
76052
76053
76054
76055
76056
76057
76058
76059
76060
76061
76062
76063
76064
76065
** pMem->zMalloc space will be allocated if necessary.  The calling routine
** is responsible for making sure that the pMem object is eventually
** destroyed.
**
** If this routine fails for any reason (malloc returns NULL or unable
** to read from the disk) then the pMem is left in an inconsistent state.
*/
static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
  BtCursor *pCur,   /* Cursor pointing at record to retrieve. */
  u32 offset,       /* Offset from the start of data to return bytes from. */
  u32 amt,          /* Number of bytes to return. */
  Mem *pMem         /* OUT: Return data in this Mem structure. */
){
  int rc;
  pMem->flags = MEM_Null;







|







76508
76509
76510
76511
76512
76513
76514
76515
76516
76517
76518
76519
76520
76521
76522
** pMem->zMalloc space will be allocated if necessary.  The calling routine
** is responsible for making sure that the pMem object is eventually
** destroyed.
**
** If this routine fails for any reason (malloc returns NULL or unable
** to read from the disk) then the pMem is left in an inconsistent state.
*/
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
  BtCursor *pCur,   /* Cursor pointing at record to retrieve. */
  u32 offset,       /* Offset from the start of data to return bytes from. */
  u32 amt,          /* Number of bytes to return. */
  Mem *pMem         /* OUT: Return data in this Mem structure. */
){
  int rc;
  pMem->flags = MEM_Null;
76074
76075
76076
76077
76078
76079
76080
76081
76082
76083
76084
76085
76086
76087
76088
76089
76090
76091
76092
76093
76094
76095
76096
76097
76098
76099
76100
76101
76102
76103
76104
76105
76106
76107
76108
76109
76110
76111
76112
      pMem->n = (int)amt;
    }else{
      sqlite3VdbeMemRelease(pMem);
    }
  }
  return rc;
}
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
  BtCursor *pCur,   /* Cursor pointing at record to retrieve. */
  u32 offset,       /* Offset from the start of data to return bytes from. */
  u32 amt,          /* Number of bytes to return. */
  Mem *pMem         /* OUT: Return data in this Mem structure. */
){
  char *zData;        /* Data from the btree layer */
  u32 available = 0;  /* Number of bytes available on the local btree page */
  int rc = SQLITE_OK; /* Return code */

  assert( sqlite3BtreeCursorIsValid(pCur) );
  assert( !VdbeMemDynamic(pMem) );

  /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() 
  ** that both the BtShared and database handle mutexes are held. */
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
  assert( zData!=0 );

  if( offset+amt<=available ){
    pMem->z = &zData[offset];
    pMem->flags = MEM_Blob|MEM_Ephem;
    pMem->n = (int)amt;
  }else{
    rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem);
  }

  return rc;
}

/*
** The pVal argument is known to be a value other than NULL.







|

<



<









|
|

|
<



|







76531
76532
76533
76534
76535
76536
76537
76538
76539

76540
76541
76542

76543
76544
76545
76546
76547
76548
76549
76550
76551
76552
76553
76554
76555

76556
76557
76558
76559
76560
76561
76562
76563
76564
76565
76566
      pMem->n = (int)amt;
    }else{
      sqlite3VdbeMemRelease(pMem);
    }
  }
  return rc;
}
SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(
  BtCursor *pCur,   /* Cursor pointing at record to retrieve. */

  u32 amt,          /* Number of bytes to return. */
  Mem *pMem         /* OUT: Return data in this Mem structure. */
){

  u32 available = 0;  /* Number of bytes available on the local btree page */
  int rc = SQLITE_OK; /* Return code */

  assert( sqlite3BtreeCursorIsValid(pCur) );
  assert( !VdbeMemDynamic(pMem) );

  /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() 
  ** that both the BtShared and database handle mutexes are held. */
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  pMem->z = (char *)sqlite3BtreePayloadFetch(pCur, &available);
  assert( pMem->z!=0 );

  if( amt<=available ){

    pMem->flags = MEM_Blob|MEM_Ephem;
    pMem->n = (int)amt;
  }else{
    rc = sqlite3VdbeMemFromBtree(pCur, 0, amt, pMem);
  }

  return rc;
}

/*
** The pVal argument is known to be a value other than NULL.
76441
76442
76443
76444
76445
76446
76447

76448



76449
76450
76451
76452
76453
76454
76455
    if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) 
     && pVal!=0
    ){
      sqlite3VdbeMemNumerify(pVal);
      if( pVal->flags & MEM_Real ){
        pVal->u.r = -pVal->u.r;
      }else if( pVal->u.i==SMALLEST_INT64 ){

        pVal->u.r = -(double)SMALLEST_INT64;



        MemSetTypeFlag(pVal, MEM_Real);
      }else{
        pVal->u.i = -pVal->u.i;
      }
      sqlite3ValueApplyAffinity(pVal, affinity, enc);
    }
  }else if( op==TK_NULL ){







>

>
>
>







76895
76896
76897
76898
76899
76900
76901
76902
76903
76904
76905
76906
76907
76908
76909
76910
76911
76912
76913
    if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) 
     && pVal!=0
    ){
      sqlite3VdbeMemNumerify(pVal);
      if( pVal->flags & MEM_Real ){
        pVal->u.r = -pVal->u.r;
      }else if( pVal->u.i==SMALLEST_INT64 ){
#ifndef SQLITE_OMIT_FLOATING_POINT
        pVal->u.r = -(double)SMALLEST_INT64;
#else
        pVal->u.r = LARGEST_INT64;
#endif
        MemSetTypeFlag(pVal, MEM_Real);
      }else{
        pVal->u.i = -pVal->u.i;
      }
      sqlite3ValueApplyAffinity(pVal, affinity, enc);
    }
  }else if( op==TK_NULL ){
76979
76980
76981
76982
76983
76984
76985
76986







76987
76988
76989
76990
76991
76992
76993
76994
76995
  }
  return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT);
}

#ifdef SQLITE_DEBUG
/* This routine is just a convenient place to set a breakpoint that will
** fire after each opcode is inserted and displayed using
** "PRAGMA vdbe_addoptrace=on".







*/
static void test_addop_breakpoint(void){
  static int n = 0;
  n++;
}
#endif

/*
** Add a new instruction to the list of instructions current in the







|
>
>
>
>
>
>
>

|







77437
77438
77439
77440
77441
77442
77443
77444
77445
77446
77447
77448
77449
77450
77451
77452
77453
77454
77455
77456
77457
77458
77459
77460
  }
  return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT);
}

#ifdef SQLITE_DEBUG
/* This routine is just a convenient place to set a breakpoint that will
** fire after each opcode is inserted and displayed using
** "PRAGMA vdbe_addoptrace=on".  Parameters "pc" (program counter) and
** pOp are available to make the breakpoint conditional.
**
** Other useful labels for breakpoints include:
**   test_trace_breakpoint(pc,pOp)
**   sqlite3CorruptError(lineno)
**   sqlite3MisuseError(lineno)
**   sqlite3CantopenError(lineno)
*/
static void test_addop_breakpoint(int pc, Op *pOp){
  static int n = 0;
  n++;
}
#endif

/*
** Add a new instruction to the list of instructions current in the
77034
77035
77036
77037
77038
77039
77040
77041
77042
77043
77044
77045
77046
77047
77048
  pOp->p4type = P4_NOTUSED;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
  pOp->zComment = 0;
#endif
#ifdef SQLITE_DEBUG
  if( p->db->flags & SQLITE_VdbeAddopTrace ){
    sqlite3VdbePrintOp(0, i, &p->aOp[i]);
    test_addop_breakpoint();
  }
#endif
#ifdef VDBE_PROFILE
  pOp->cycles = 0;
  pOp->cnt = 0;
#endif
#ifdef SQLITE_VDBE_COVERAGE







|







77499
77500
77501
77502
77503
77504
77505
77506
77507
77508
77509
77510
77511
77512
77513
  pOp->p4type = P4_NOTUSED;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
  pOp->zComment = 0;
#endif
#ifdef SQLITE_DEBUG
  if( p->db->flags & SQLITE_VdbeAddopTrace ){
    sqlite3VdbePrintOp(0, i, &p->aOp[i]);
    test_addop_breakpoint(i, &p->aOp[i]);
  }
#endif
#ifdef VDBE_PROFILE
  pOp->cycles = 0;
  pOp->cnt = 0;
#endif
#ifdef SQLITE_VDBE_COVERAGE
77202
77203
77204
77205
77206
77207
77208
77209
77210
77211
77212
77213
77214
77215
77216
SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){
  (void)z1;
  (void)z2;
}
#endif

/*
** Add a new OP_ opcode.
**
** If the bPush flag is true, then make this opcode the parent for
** subsequent Explains until sqlite3VdbeExplainPop() is called.
*/
SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
#ifndef SQLITE_DEBUG
  /* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.







|







77667
77668
77669
77670
77671
77672
77673
77674
77675
77676
77677
77678
77679
77680
77681
SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){
  (void)z1;
  (void)z2;
}
#endif

/*
** Add a new OP_Explain opcode.
**
** If the bPush flag is true, then make this opcode the parent for
** subsequent Explains until sqlite3VdbeExplainPop() is called.
*/
SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
#ifndef SQLITE_DEBUG
  /* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
77452
77453
77454
77455
77456
77457
77458

77459
77460
77461
77462
77463
77464
77465
** to be rolled back). This condition is true if the main program or any
** sub-programs contains any of the following:
**
**   *  OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
**   *  OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
**   *  OP_Destroy
**   *  OP_VUpdate

**   *  OP_VRename
**   *  OP_FkCounter with P2==0 (immediate foreign key constraint)
**   *  OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine 
**      (for CREATE TABLE AS SELECT ...)
**
** Then check that the value of Parse.mayAbort is true if an
** ABORT may be thrown, or false otherwise. Return true if it does







>







77917
77918
77919
77920
77921
77922
77923
77924
77925
77926
77927
77928
77929
77930
77931
** to be rolled back). This condition is true if the main program or any
** sub-programs contains any of the following:
**
**   *  OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
**   *  OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
**   *  OP_Destroy
**   *  OP_VUpdate
**   *  OP_VCreate
**   *  OP_VRename
**   *  OP_FkCounter with P2==0 (immediate foreign key constraint)
**   *  OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine 
**      (for CREATE TABLE AS SELECT ...)
**
** Then check that the value of Parse.mayAbort is true if an
** ABORT may be thrown, or false otherwise. Return true if it does
77479
77480
77481
77482
77483
77484
77485

77486
77487
77488
77489
77490
77491
77492
  memset(&sIter, 0, sizeof(sIter));
  sIter.v = v;

  while( (pOp = opIterNext(&sIter))!=0 ){
    int opcode = pOp->opcode;
    if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename 
     || opcode==OP_VDestroy

     || (opcode==OP_ParseSchema && pOp->p4.z==0)
     || ((opcode==OP_Halt || opcode==OP_HaltIfNull) 
      && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
    ){
      hasAbort = 1;
      break;
    }







>







77945
77946
77947
77948
77949
77950
77951
77952
77953
77954
77955
77956
77957
77958
77959
  memset(&sIter, 0, sizeof(sIter));
  sIter.v = v;

  while( (pOp = opIterNext(&sIter))!=0 ){
    int opcode = pOp->opcode;
    if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename 
     || opcode==OP_VDestroy
     || opcode==OP_VCreate
     || (opcode==OP_ParseSchema && pOp->p4.z==0)
     || ((opcode==OP_Halt || opcode==OP_HaltIfNull) 
      && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
    ){
      hasAbort = 1;
      break;
    }
77841
77842
77843
77844
77845
77846
77847




























77848
77849
77850
77851
77852
77853
77854
** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
  sqlite3VdbeChangeP2(p, addr, p->nOp);
}






























/*
** If the input FuncDef structure is ephemeral, then free it.  If
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
  if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){







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







78308
78309
78310
78311
78312
78313
78314
78315
78316
78317
78318
78319
78320
78321
78322
78323
78324
78325
78326
78327
78328
78329
78330
78331
78332
78333
78334
78335
78336
78337
78338
78339
78340
78341
78342
78343
78344
78345
78346
78347
78348
78349
** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
  sqlite3VdbeChangeP2(p, addr, p->nOp);
}

/*
** Change the P2 operand of the jump instruction at addr so that
** the jump lands on the next opcode.  Or if the jump instruction was
** the previous opcode (and is thus a no-op) then simply back up
** the next instruction counter by one slot so that the jump is
** overwritten by the next inserted opcode.
**
** This routine is an optimization of sqlite3VdbeJumpHere() that
** strives to omit useless byte-code like this:
**
**        7   Once 0 8 0
**        8   ...
*/
SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
  if( addr==p->nOp-1 ){
    assert( p->aOp[addr].opcode==OP_Once
         || p->aOp[addr].opcode==OP_If
         || p->aOp[addr].opcode==OP_FkIfZero );
    assert( p->aOp[addr].p4type==0 );
#ifdef SQLITE_VDBE_COVERAGE
    sqlite3VdbeGetOp(p,-1)->iSrcLine = 0;  /* Erase VdbeCoverage() macros */
#endif
    p->nOp--;
  }else{
    sqlite3VdbeChangeP2(p, addr, p->nOp);
  }
}


/*
** If the input FuncDef structure is ephemeral, then free it.  If
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
  if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
77968
77969
77970
77971
77972
77973
77974



































77975
77976
77977
77978
77979
77980
77981
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
  if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){
    return sqlite3VdbeChangeToNoop(p, p->nOp-1);
  }else{
    return 0;
  }
}




































/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
** static array using sqlite3VdbeAddOpList but we want to make a
** few minor changes to the program.
**







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







78463
78464
78465
78466
78467
78468
78469
78470
78471
78472
78473
78474
78475
78476
78477
78478
78479
78480
78481
78482
78483
78484
78485
78486
78487
78488
78489
78490
78491
78492
78493
78494
78495
78496
78497
78498
78499
78500
78501
78502
78503
78504
78505
78506
78507
78508
78509
78510
78511
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
  if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){
    return sqlite3VdbeChangeToNoop(p, p->nOp-1);
  }else{
    return 0;
  }
}

#ifdef SQLITE_DEBUG
/*
** Generate an OP_ReleaseReg opcode to indicate that a range of
** registers, except any identified by mask, are no longer in use.
*/
SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(
  Parse *pParse,       /* Parsing context */
  int iFirst,          /* Index of first register to be released */
  int N,               /* Number of registers to release */
  u32 mask,            /* Mask of registers to NOT release */
  int bUndefine        /* If true, mark registers as undefined */
){
  if( N==0 ) return;
  assert( pParse->pVdbe );
  assert( iFirst>=1 );
  assert( iFirst+N-1<=pParse->nMem );
  if( N<=31 && mask!=0 ){
    while( N>0 && (mask&1)!=0 ){
      mask >>= 1;
      iFirst++;
      N--;
    }
    while( N>0 && N<=32 && (mask & MASKBIT32(N-1))!=0 ){
      mask &= ~MASKBIT32(N-1);
      N--;
    }
  }
  if( N>0 ){
    sqlite3VdbeAddOp3(pParse->pVdbe, OP_ReleaseReg, iFirst, N, *(int*)&mask);
    if( bUndefine ) sqlite3VdbeChangeP5(pParse->pVdbe, 1);
  }
}
#endif /* SQLITE_DEBUG */


/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
** static array using sqlite3VdbeAddOpList but we want to make a
** few minor changes to the program.
**
78086
78087
78088
78089
78090
78091
78092
78093

78094
78095
78096
78097
78098
78099
78100
** Change the comment on the most recently coded instruction.  Or
** insert a No-op and add the comment to that new instruction.  This
** makes the code easier to read during debugging.  None of this happens
** in a production build.
*/
static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){
  assert( p->nOp>0 || p->aOp==0 );
  assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed );

  if( p->nOp ){
    assert( p->aOp );
    sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);
    p->aOp[p->nOp-1].zComment = sqlite3VMPrintf(p->db, zFormat, ap);
  }
}
SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){







|
>







78616
78617
78618
78619
78620
78621
78622
78623
78624
78625
78626
78627
78628
78629
78630
78631
** Change the comment on the most recently coded instruction.  Or
** insert a No-op and add the comment to that new instruction.  This
** makes the code easier to read during debugging.  None of this happens
** in a production build.
*/
static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){
  assert( p->nOp>0 || p->aOp==0 );
  assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed
          || p->pParse->nErr>0 );
  if( p->nOp ){
    assert( p->aOp );
    sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);
    p->aOp[p->nOp-1].zComment = sqlite3VMPrintf(p->db, zFormat, ap);
  }
}
SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
78185
78186
78187
78188
78189
78190
78191
78192
78193



78194
78195
78196
78197
78198
78199
78200
78201
78202
78203
78204
78205
78206
78207
78208
78209
78210
78211
78212
78213
78214
78215
78216
78217
78218
78219
78220
78221
78222
78223
78224
78225
78226
78227
78228
78229


78230














78231
78232
78233
78234
78235

78236
78237

78238
78239
78240
78241
78242
78243
78244
78245
78246
78247
78248
78249
78250
78251

78252
78253
78254
78255
78256
78257
78258
78259
  const char *zP4,   /* Previously obtained value for P4 */
  char *zTemp,       /* Write result here */
  int nTemp          /* Space available in zTemp[] */
){
  const char *zOpName;
  const char *zSynopsis;
  int nOpName;
  int ii, jj;
  char zAlt[50];



  zOpName = sqlite3OpcodeName(pOp->opcode);
  nOpName = sqlite3Strlen30(zOpName);
  if( zOpName[nOpName+1] ){
    int seenCom = 0;
    char c;
    zSynopsis = zOpName += nOpName + 1;
    if( strncmp(zSynopsis,"IF ",3)==0 ){
      if( pOp->p5 & SQLITE_STOREP2 ){
        sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3);
      }else{
        sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
      }
      zSynopsis = zAlt;
    }
    for(ii=jj=0; jj<nTemp-1 && (c = zSynopsis[ii])!=0; ii++){
      if( c=='P' ){
        c = zSynopsis[++ii];
        if( c=='4' ){
          sqlite3_snprintf(nTemp-jj, zTemp+jj, "%s", zP4);
        }else if( c=='X' ){
          sqlite3_snprintf(nTemp-jj, zTemp+jj, "%s", pOp->zComment);
          seenCom = 1;
        }else{
          int v1 = translateP(c, pOp);
          int v2;
          sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
          if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
            ii += 3;
            jj += sqlite3Strlen30(zTemp+jj);
            v2 = translateP(zSynopsis[ii], pOp);
            if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
              ii += 2;
              v2++;
            }
            if( v2>1 ){
              sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);


            }














          }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
            ii += 4;
          }
        }
        jj += sqlite3Strlen30(zTemp+jj);

      }else{
        zTemp[jj++] = c;

      }
    }
    if( !seenCom && jj<nTemp-5 && pOp->zComment ){
      sqlite3_snprintf(nTemp-jj, zTemp+jj, "; %s", pOp->zComment);
      jj += sqlite3Strlen30(zTemp+jj);
    }
    if( jj<nTemp ) zTemp[jj] = 0;
  }else if( pOp->zComment ){
    sqlite3_snprintf(nTemp, zTemp, "%s", pOp->zComment);
    jj = sqlite3Strlen30(zTemp);
  }else{
    zTemp[0] = 0;
    jj = 0;
  }

  return jj;
}
#endif /* SQLITE_DEBUG */

#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
/*
** Translate the P4.pExpr value for an OP_CursorHint opcode into text
** that can be displayed in the P4 column of EXPLAIN output.







|

>
>
>














|



|

|




<


<





|
|
>
>

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

<
>


|
|
<

<

|
<
<
<
<

>
|







78716
78717
78718
78719
78720
78721
78722
78723
78724
78725
78726
78727
78728
78729
78730
78731
78732
78733
78734
78735
78736
78737
78738
78739
78740
78741
78742
78743
78744
78745
78746
78747
78748
78749
78750
78751
78752

78753
78754

78755
78756
78757
78758
78759
78760
78761
78762
78763
78764
78765
78766
78767
78768
78769
78770
78771
78772
78773
78774
78775
78776
78777
78778
78779
78780
78781
78782

78783
78784

78785
78786
78787
78788
78789

78790

78791
78792




78793
78794
78795
78796
78797
78798
78799
78800
78801
78802
  const char *zP4,   /* Previously obtained value for P4 */
  char *zTemp,       /* Write result here */
  int nTemp          /* Space available in zTemp[] */
){
  const char *zOpName;
  const char *zSynopsis;
  int nOpName;
  int ii;
  char zAlt[50];
  StrAccum x;
  sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);

  zOpName = sqlite3OpcodeName(pOp->opcode);
  nOpName = sqlite3Strlen30(zOpName);
  if( zOpName[nOpName+1] ){
    int seenCom = 0;
    char c;
    zSynopsis = zOpName += nOpName + 1;
    if( strncmp(zSynopsis,"IF ",3)==0 ){
      if( pOp->p5 & SQLITE_STOREP2 ){
        sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3);
      }else{
        sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
      }
      zSynopsis = zAlt;
    }
    for(ii=0; (c = zSynopsis[ii])!=0; ii++){
      if( c=='P' ){
        c = zSynopsis[++ii];
        if( c=='4' ){
          sqlite3_str_appendall(&x, zP4);
        }else if( c=='X' ){
          sqlite3_str_appendall(&x, pOp->zComment);
          seenCom = 1;
        }else{
          int v1 = translateP(c, pOp);
          int v2;

          if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
            ii += 3;

            v2 = translateP(zSynopsis[ii], pOp);
            if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
              ii += 2;
              v2++;
            }
            if( v2<2 ){
              sqlite3_str_appendf(&x, "%d", v1);
            }else{
              sqlite3_str_appendf(&x, "%d..%d", v1, v1+v2-1);
            }
          }else if( strncmp(zSynopsis+ii+1, "@NP", 3)==0 ){
            sqlite3_context *pCtx = pOp->p4.pCtx;
            if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){
              sqlite3_str_appendf(&x, "%d", v1);
            }else if( pCtx->argc>1 ){
              sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1);
            }else{
              assert( x.nChar>2 );
              x.nChar -= 2;
              ii++;
            }
            ii += 3;
          }else{
            sqlite3_str_appendf(&x, "%d", v1);
            if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
              ii += 4;
            }
          }

        }
      }else{

        sqlite3_str_appendchar(&x, 1, c);
      }
    }
    if( !seenCom && pOp->zComment ){
      sqlite3_str_appendf(&x, "; %s", pOp->zComment);

    }

  }else if( pOp->zComment ){
    sqlite3_str_appendall(&x, pOp->zComment);




  }
  sqlite3StrAccumFinish(&x);
  return x.nChar;
}
#endif /* SQLITE_DEBUG */

#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
/*
** Translate the P4.pExpr value for an OP_CursorHint opcode into text
** that can be displayed in the P4 column of EXPLAIN output.
78358
78359
78360
78361
78362
78363
78364

78365

78366

78367
78368
78369
78370
78371
78372
78373
#ifdef SQLITE_ENABLE_CURSOR_HINTS
    case P4_EXPR: {
      displayP4Expr(&x, pOp->p4.pExpr);
      break;
    }
#endif
    case P4_COLLSEQ: {

      CollSeq *pColl = pOp->p4.pColl;

      sqlite3_str_appendf(&x, "(%.20s)", pColl->zName);

      break;
    }
    case P4_FUNCDEF: {
      FuncDef *pDef = pOp->p4.pFunc;
      sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg);
      break;
    }







>

>
|
>







78901
78902
78903
78904
78905
78906
78907
78908
78909
78910
78911
78912
78913
78914
78915
78916
78917
78918
78919
#ifdef SQLITE_ENABLE_CURSOR_HINTS
    case P4_EXPR: {
      displayP4Expr(&x, pOp->p4.pExpr);
      break;
    }
#endif
    case P4_COLLSEQ: {
      static const char *const encnames[] = {"?", "8", "16LE", "16BE"};
      CollSeq *pColl = pOp->p4.pColl;
      assert( pColl->enc>=0 && pColl->enc<4 );
      sqlite3_str_appendf(&x, "%.18s-%s", pColl->zName,
                          encnames[pColl->enc]);
      break;
    }
    case P4_FUNCDEF: {
      FuncDef *pDef = pOp->p4.pFunc;
      sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg);
      break;
    }
78790
78791
78792
78793
78794
78795
78796
78797
78798
78799
78800
78801
78802
78803
78804
    }
    if( p->explain<2 ) break;
    if( pOp->opcode==OP_Explain ) break;
    if( pOp->opcode==OP_Init && p->pc>1 ) break;
  }

  if( rc==SQLITE_OK ){
    if( db->u1.isInterrupted ){
      p->rc = SQLITE_INTERRUPT;
      rc = SQLITE_ERROR;
      sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
    }else{
      char *zP4;
      if( p->explain==1 ){
        pMem->flags = MEM_Int;







|







79336
79337
79338
79339
79340
79341
79342
79343
79344
79345
79346
79347
79348
79349
79350
    }
    if( p->explain<2 ) break;
    if( pOp->opcode==OP_Explain ) break;
    if( pOp->opcode==OP_Init && p->pc>1 ) break;
  }

  if( rc==SQLITE_OK ){
    if( AtomicLoad(&db->u1.isInterrupted) ){
      p->rc = SQLITE_INTERRUPT;
      rc = SQLITE_ERROR;
      sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
    }else{
      char *zP4;
      if( p->explain==1 ){
        pMem->flags = MEM_Int;
79072
79073
79074
79075
79076
79077
79078

79079
79080
79081
79082
79083
79084
79085
  if( pParse->explain ){
    static const char * const azColName[] = {
       "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
       "id", "parent", "notused", "detail"
    };
    int iFirst, mx, i;
    if( nMem<10 ) nMem = 10;

    if( pParse->explain==2 ){
      sqlite3VdbeSetNumCols(p, 4);
      iFirst = 8;
      mx = 12;
    }else{
      sqlite3VdbeSetNumCols(p, 8);
      iFirst = 0;







>







79618
79619
79620
79621
79622
79623
79624
79625
79626
79627
79628
79629
79630
79631
79632
  if( pParse->explain ){
    static const char * const azColName[] = {
       "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
       "id", "parent", "notused", "detail"
    };
    int iFirst, mx, i;
    if( nMem<10 ) nMem = 10;
    p->explain = pParse->explain;
    if( pParse->explain==2 ){
      sqlite3VdbeSetNumCols(p, 4);
      iFirst = 8;
      mx = 12;
    }else{
      sqlite3VdbeSetNumCols(p, 8);
      iFirst = 0;
79122
79123
79124
79125
79126
79127
79128
79129
79130
79131
79132
79133
79134
79135
79136
      p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
#endif
    }
  }

  p->pVList = pParse->pVList;
  pParse->pVList =  0;
  p->explain = pParse->explain;
  if( db->mallocFailed ){
    p->nVar = 0;
    p->nCursor = 0;
    p->nMem = 0;
  }else{
    p->nCursor = nCursor;
    p->nVar = (ynVar)nVar;







<







79669
79670
79671
79672
79673
79674
79675

79676
79677
79678
79679
79680
79681
79682
      p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
#endif
    }
  }

  p->pVList = pParse->pVList;
  pParse->pVList =  0;

  if( db->mallocFailed ){
    p->nVar = 0;
    p->nCursor = 0;
    p->nMem = 0;
  }else{
    p->nCursor = nCursor;
    p->nVar = (ynVar)nVar;
80173
80174
80175
80176
80177
80178
80179
80180
80181
80182
80183
80184
80185
80186
80187
}

/*
** The cursor "p" has a pending seek operation that has not yet been
** carried out.  Seek the cursor now.  If an error occurs, return
** the appropriate error code.
*/
static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
  int res, rc;
#ifdef SQLITE_TEST
  extern int sqlite3_search_count;
#endif
  assert( p->deferredMoveto );
  assert( p->isTable );
  assert( p->eCurType==CURTYPE_BTREE );







|







80719
80720
80721
80722
80723
80724
80725
80726
80727
80728
80729
80730
80731
80732
80733
}

/*
** The cursor "p" has a pending seek operation that has not yet been
** carried out.  Seek the cursor now.  If an error occurs, return
** the appropriate error code.
*/
SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
  int res, rc;
#ifdef SQLITE_TEST
  extern int sqlite3_search_count;
#endif
  assert( p->deferredMoveto );
  assert( p->isTable );
  assert( p->eCurType==CURTYPE_BTREE );
80240
80241
80242
80243
80244
80245
80246
80247
80248
80249
80250
80251
80252
80253
80254
80255
80256
80257
80258
80259
** not been deleted out from under the cursor, then this routine is a no-op.
*/
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
  VdbeCursor *p = *pp;
  assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
  if( p->deferredMoveto ){
    int iMap;
    if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
      *pp = p->pAltCursor;
      *piCol = iMap - 1;
      return SQLITE_OK;
    }
    return handleDeferredMoveto(p);
  }
  if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
    return handleMovedCursor(p);
  }
  return SQLITE_OK;
}








|




|







80786
80787
80788
80789
80790
80791
80792
80793
80794
80795
80796
80797
80798
80799
80800
80801
80802
80803
80804
80805
** not been deleted out from under the cursor, then this routine is a no-op.
*/
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
  VdbeCursor *p = *pp;
  assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
  if( p->deferredMoveto ){
    int iMap;
    if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
      *pp = p->pAltCursor;
      *piCol = iMap - 1;
      return SQLITE_OK;
    }
    return sqlite3VdbeFinishMoveto(p);
  }
  if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
    return handleMovedCursor(p);
  }
  return SQLITE_OK;
}

81243
81244
81245
81246
81247
81248
81249
81250
81251
81252
81253
81254
81255
81256
81257
          rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
        }
      }
    }

    /* RHS is a string */
    else if( pRhs->flags & MEM_Str ){
      getVarint32(&aKey1[idx1], serial_type);
      testcase( serial_type==12 );
      if( serial_type<12 ){
        rc = -1;
      }else if( !(serial_type & 0x01) ){
        rc = +1;
      }else{
        mem1.n = (serial_type - 12) / 2;







|







81789
81790
81791
81792
81793
81794
81795
81796
81797
81798
81799
81800
81801
81802
81803
          rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
        }
      }
    }

    /* RHS is a string */
    else if( pRhs->flags & MEM_Str ){
      getVarint32NR(&aKey1[idx1], serial_type);
      testcase( serial_type==12 );
      if( serial_type<12 ){
        rc = -1;
      }else if( !(serial_type & 0x01) ){
        rc = +1;
      }else{
        mem1.n = (serial_type - 12) / 2;
81277
81278
81279
81280
81281
81282
81283
81284
81285
81286
81287
81288
81289
81290
81291
        }
      }
    }

    /* RHS is a blob */
    else if( pRhs->flags & MEM_Blob ){
      assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 );
      getVarint32(&aKey1[idx1], serial_type);
      testcase( serial_type==12 );
      if( serial_type<12 || (serial_type & 0x01) ){
        rc = -1;
      }else{
        int nStr = (serial_type - 12) / 2;
        testcase( (d1+nStr)==(unsigned)nKey1 );
        testcase( (d1+nStr+1)==(unsigned)nKey1 );







|







81823
81824
81825
81826
81827
81828
81829
81830
81831
81832
81833
81834
81835
81836
81837
        }
      }
    }

    /* RHS is a blob */
    else if( pRhs->flags & MEM_Blob ){
      assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 );
      getVarint32NR(&aKey1[idx1], serial_type);
      testcase( serial_type==12 );
      if( serial_type<12 || (serial_type & 0x01) ){
        rc = -1;
      }else{
        int nStr = (serial_type - 12) / 2;
        testcase( (d1+nStr)==(unsigned)nKey1 );
        testcase( (d1+nStr+1)==(unsigned)nKey1 );
81466
81467
81468
81469
81470
81471
81472


81473

81474
81475
81476
81477
81478
81479
81480
){
  const u8 *aKey1 = (const u8*)pKey1;
  int serial_type;
  int res;

  assert( pPKey2->aMem[0].flags & MEM_Str );
  vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);


  getVarint32(&aKey1[1], serial_type);

  if( serial_type<12 ){
    res = pPKey2->r1;      /* (pKey1/nKey1) is a number or a null */
  }else if( !(serial_type & 0x01) ){ 
    res = pPKey2->r2;      /* (pKey1/nKey1) is a blob */
  }else{
    int nCmp;
    int nStr;







>
>
|
>







82012
82013
82014
82015
82016
82017
82018
82019
82020
82021
82022
82023
82024
82025
82026
82027
82028
82029
){
  const u8 *aKey1 = (const u8*)pKey1;
  int serial_type;
  int res;

  assert( pPKey2->aMem[0].flags & MEM_Str );
  vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
  serial_type = (u8)(aKey1[1]);
  if( serial_type >= 0x80 ){
    sqlite3GetVarint32(&aKey1[1], (u32*)&serial_type);
  }
  if( serial_type<12 ){
    res = pPKey2->r1;      /* (pKey1/nKey1) is a number or a null */
  }else if( !(serial_type & 0x01) ){ 
    res = pPKey2->r2;      /* (pKey1/nKey1) is a blob */
  }else{
    int nCmp;
    int nStr;
81587
81588
81589
81590
81591
81592
81593
81594
81595
81596
81597
81598
81599
81600
81601
81602
81603
81604
81605
81606
81607
81608
81609
81610
81611
81612
81613
81614
81615
81616
81617
81618
  */
  assert( sqlite3BtreeCursorIsValid(pCur) );
  nCellKey = sqlite3BtreePayloadSize(pCur);
  assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );

  /* Read in the complete content of the index entry */
  sqlite3VdbeMemInit(&m, db, 0);
  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
  if( rc ){
    return rc;
  }

  /* The index entry must begin with a header size */
  (void)getVarint32((u8*)m.z, szHdr);
  testcase( szHdr==3 );
  testcase( szHdr==m.n );
  testcase( szHdr>0x7fffffff );
  assert( m.n>=0 );
  if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){
    goto idx_rowid_corruption;
  }

  /* The last field of the index should be an integer - the ROWID.
  ** Verify that the last entry really is an integer. */
  (void)getVarint32((u8*)&m.z[szHdr-1], typeRowid);
  testcase( typeRowid==1 );
  testcase( typeRowid==2 );
  testcase( typeRowid==3 );
  testcase( typeRowid==4 );
  testcase( typeRowid==5 );
  testcase( typeRowid==6 );
  testcase( typeRowid==8 );







|





|










|







82136
82137
82138
82139
82140
82141
82142
82143
82144
82145
82146
82147
82148
82149
82150
82151
82152
82153
82154
82155
82156
82157
82158
82159
82160
82161
82162
82163
82164
82165
82166
82167
  */
  assert( sqlite3BtreeCursorIsValid(pCur) );
  nCellKey = sqlite3BtreePayloadSize(pCur);
  assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );

  /* Read in the complete content of the index entry */
  sqlite3VdbeMemInit(&m, db, 0);
  rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m);
  if( rc ){
    return rc;
  }

  /* The index entry must begin with a header size */
  getVarint32NR((u8*)m.z, szHdr);
  testcase( szHdr==3 );
  testcase( szHdr==m.n );
  testcase( szHdr>0x7fffffff );
  assert( m.n>=0 );
  if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){
    goto idx_rowid_corruption;
  }

  /* The last field of the index should be an integer - the ROWID.
  ** Verify that the last entry really is an integer. */
  getVarint32NR((u8*)&m.z[szHdr-1], typeRowid);
  testcase( typeRowid==1 );
  testcase( typeRowid==2 );
  testcase( typeRowid==3 );
  testcase( typeRowid==4 );
  testcase( typeRowid==5 );
  testcase( typeRowid==6 );
  testcase( typeRowid==8 );
81669
81670
81671
81672
81673
81674
81675
81676
81677
81678
81679
81680
81681
81682
81683
  /* nCellKey will always be between 0 and 0xffffffff because of the way
  ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
  if( nCellKey<=0 || nCellKey>0x7fffffff ){
    *res = 0;
    return SQLITE_CORRUPT_BKPT;
  }
  sqlite3VdbeMemInit(&m, db, 0);
  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
  if( rc ){
    return rc;
  }
  *res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0);
  sqlite3VdbeMemRelease(&m);
  return SQLITE_OK;
}







|







82218
82219
82220
82221
82222
82223
82224
82225
82226
82227
82228
82229
82230
82231
82232
  /* nCellKey will always be between 0 and 0xffffffff because of the way
  ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
  if( nCellKey<=0 || nCellKey>0x7fffffff ){
    *res = 0;
    return SQLITE_CORRUPT_BKPT;
  }
  sqlite3VdbeMemInit(&m, db, 0);
  rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m);
  if( rc ){
    return rc;
  }
  *res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0);
  sqlite3VdbeMemRelease(&m);
  return SQLITE_OK;
}
82582
82583
82584
82585
82586
82587
82588
82589
82590
82591
82592
82593
82594
82595
82596
  }
  if( p->pc<0 ){
    /* If there are no other statements currently running, then
    ** reset the interrupt flag.  This prevents a call to sqlite3_interrupt
    ** from interrupting a statement that has not yet started.
    */
    if( db->nVdbeActive==0 ){
      db->u1.isInterrupted = 0;
    }

    assert( db->nVdbeWrite>0 || db->autoCommit==0 
        || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
    );

#ifndef SQLITE_OMIT_TRACE







|







83131
83132
83133
83134
83135
83136
83137
83138
83139
83140
83141
83142
83143
83144
83145
  }
  if( p->pc<0 ){
    /* If there are no other statements currently running, then
    ** reset the interrupt flag.  This prevents a call to sqlite3_interrupt
    ** from interrupting a statement that has not yet started.
    */
    if( db->nVdbeActive==0 ){
      AtomicStore(&db->u1.isInterrupted, 0);
    }

    assert( db->nVdbeWrite>0 || db->autoCommit==0 
        || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
    );

#ifndef SQLITE_OMIT_TRACE
84288
84289
84290
84291
84292
84293
84294




















84295
84296
84297
84298
84299
84300
84301
*/
#if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE)
# define UPDATE_MAX_BLOBSIZE(P)  updateMaxBlobsize(P)
#else
# define UPDATE_MAX_BLOBSIZE(P)
#endif





















/*
** Invoke the VDBE coverage callback, if that callback is defined.  This
** feature is used for test suite validation only and does not appear an
** production builds.
**
** M is the type of branch.  I is the direction taken for this instance of
** the branch.







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







84837
84838
84839
84840
84841
84842
84843
84844
84845
84846
84847
84848
84849
84850
84851
84852
84853
84854
84855
84856
84857
84858
84859
84860
84861
84862
84863
84864
84865
84866
84867
84868
84869
84870
*/
#if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE)
# define UPDATE_MAX_BLOBSIZE(P)  updateMaxBlobsize(P)
#else
# define UPDATE_MAX_BLOBSIZE(P)
#endif

#ifdef SQLITE_DEBUG
/* This routine provides a convenient place to set a breakpoint during
** tracing with PRAGMA vdbe_trace=on.  The breakpoint fires right after
** each opcode is printed.  Variables "pc" (program counter) and pOp are
** available to add conditionals to the breakpoint.  GDB example:
**
**         break test_trace_breakpoint if pc=22
**
** Other useful labels for breakpoints include:
**   test_addop_breakpoint(pc,pOp)
**   sqlite3CorruptError(lineno)
**   sqlite3MisuseError(lineno)
**   sqlite3CantopenError(lineno)
*/
static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
  static int n = 0;
  n++;
}
#endif

/*
** Invoke the VDBE coverage callback, if that callback is defined.  This
** feature is used for test suite validation only and does not appear an
** production builds.
**
** M is the type of branch.  I is the direction taken for this instance of
** the branch.
84632
84633
84634
84635
84636
84637
84638
84639
84640
84641
84642
84643
84644
84645
84646
84647
84648
84649
84650
84651
84652
84653
84654
84655
84656
84657
84658
84659
84660
84661
84662
84663
84664
84665
84666
84667
84668

84669
84670
84671
84672

84673
84674

84675
84676
84677
84678
84679
84680
84681
84682
84683
84684
84685
84686
84687
84688
84689
84690
84691
84692
84693
84694
84695
84696
84697
84698
84699
84700
84701
84702
84703
84704
84705
84706
84707
84708
84709
84710
84711
84712
84713
84714
84715
84716
84717
}

#ifdef SQLITE_DEBUG
/*
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
*/
SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
  char *zCsr = zBuf;
  int f = pMem->flags;

  static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"};

  if( f&MEM_Blob ){
    int i;
    char c;
    if( f & MEM_Dyn ){
      c = 'z';
      assert( (f & (MEM_Static|MEM_Ephem))==0 );
    }else if( f & MEM_Static ){
      c = 't';
      assert( (f & (MEM_Dyn|MEM_Ephem))==0 );
    }else if( f & MEM_Ephem ){
      c = 'e';
      assert( (f & (MEM_Static|MEM_Dyn))==0 );
    }else{
      c = 's';
    }
    *(zCsr++) = c;
    *(zCsr++) = 'x';
    sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
    zCsr += sqlite3Strlen30(zCsr);
    for(i=0; i<25 && i<pMem->n; i++){
      sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
      zCsr += sqlite3Strlen30(zCsr);
    }
    *zCsr++ = '|';

    for(i=0; i<25 && i<pMem->n; i++){
      char z = pMem->z[i];
      if( z<32 || z>126 ) *zCsr++ = '.';
      else *zCsr++ = z;

    }
    *(zCsr++) = ']';

    if( f & MEM_Zero ){
      sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero);
      zCsr += sqlite3Strlen30(zCsr);
    }
    *zCsr = '\0';
  }else if( f & MEM_Str ){
    int j, k;
    zBuf[0] = ' ';
    if( f & MEM_Dyn ){
      zBuf[1] = 'z';
      assert( (f & (MEM_Static|MEM_Ephem))==0 );
    }else if( f & MEM_Static ){
      zBuf[1] = 't';
      assert( (f & (MEM_Dyn|MEM_Ephem))==0 );
    }else if( f & MEM_Ephem ){
      zBuf[1] = 'e';
      assert( (f & (MEM_Static|MEM_Dyn))==0 );
    }else{
      zBuf[1] = 's';
    }
    k = 2;
    sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n);
    k += sqlite3Strlen30(&zBuf[k]);
    zBuf[k++] = '[';
    for(j=0; j<25 && j<pMem->n; j++){
      u8 c = pMem->z[j];
      if( c>=0x20 && c<0x7f ){
        zBuf[k++] = c;
      }else{
        zBuf[k++] = '.';
      }
    }
    zBuf[k++] = ']';
    sqlite3_snprintf(100,&zBuf[k], encnames[pMem->enc]);
    k += sqlite3Strlen30(&zBuf[k]);
    zBuf[k++] = 0;
  }
}
#endif

#ifdef SQLITE_DEBUG
/*
** Print the value of a register for tracing purposes:







|
<

<

<















<
<
|
<

|
<

<
>


<
<
>

<
>

|
<

<

|
|

|


|


|


|

<
|
<
<

|
|
<
<
<
|
<
<
|
<
<







85201
85202
85203
85204
85205
85206
85207
85208

85209

85210

85211
85212
85213
85214
85215
85216
85217
85218
85219
85220
85221
85222
85223
85224
85225


85226

85227
85228

85229

85230
85231
85232


85233
85234

85235
85236
85237

85238

85239
85240
85241
85242
85243
85244
85245
85246
85247
85248
85249
85250
85251
85252
85253

85254


85255
85256
85257



85258


85259


85260
85261
85262
85263
85264
85265
85266
}

#ifdef SQLITE_DEBUG
/*
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
*/
SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){

  int f = pMem->flags;

  static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"};

  if( f&MEM_Blob ){
    int i;
    char c;
    if( f & MEM_Dyn ){
      c = 'z';
      assert( (f & (MEM_Static|MEM_Ephem))==0 );
    }else if( f & MEM_Static ){
      c = 't';
      assert( (f & (MEM_Dyn|MEM_Ephem))==0 );
    }else if( f & MEM_Ephem ){
      c = 'e';
      assert( (f & (MEM_Static|MEM_Dyn))==0 );
    }else{
      c = 's';
    }


    sqlite3_str_appendf(pStr, "%cx[", c);

    for(i=0; i<25 && i<pMem->n; i++){
      sqlite3_str_appendf(pStr, "%02X", ((int)pMem->z[i] & 0xFF));

    }

    sqlite3_str_appendf(pStr, "|");
    for(i=0; i<25 && i<pMem->n; i++){
      char z = pMem->z[i];


      sqlite3_str_appendchar(pStr, 1, (z<32||z>126)?'.':z);
    }

    sqlite3_str_appendf(pStr,"]");
    if( f & MEM_Zero ){
      sqlite3_str_appendf(pStr, "+%dz",pMem->u.nZero);

    }

  }else if( f & MEM_Str ){
    int j;
    u8 c;
    if( f & MEM_Dyn ){
      c = 'z';
      assert( (f & (MEM_Static|MEM_Ephem))==0 );
    }else if( f & MEM_Static ){
      c = 't';
      assert( (f & (MEM_Dyn|MEM_Ephem))==0 );
    }else if( f & MEM_Ephem ){
      c = 'e';
      assert( (f & (MEM_Static|MEM_Dyn))==0 );
    }else{
      c = 's';
    }

    sqlite3_str_appendf(pStr, " %c%d[", c, pMem->n);


    for(j=0; j<25 && j<pMem->n; j++){
      c = pMem->z[j];
      sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');



    }


    sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);


  }
}
#endif

#ifdef SQLITE_DEBUG
/*
** Print the value of a register for tracing purposes:
84730
84731
84732
84733
84734
84735
84736

84737

84738
84739
84740
84741
84742
84743
84744
84745



84746
84747
84748
84749












84750
84751
84752
84753
84754
84755
84756
#ifndef SQLITE_OMIT_FLOATING_POINT
  }else if( p->flags & MEM_Real ){
    printf(" r:%.17g", p->u.r);
#endif
  }else if( sqlite3VdbeMemIsRowSet(p) ){
    printf(" (rowset)");
  }else{

    char zBuf[200];

    sqlite3VdbeMemPrettyPrint(p, zBuf);
    printf(" %s", zBuf);
  }
  if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
}
static void registerTrace(int iReg, Mem *p){
  printf("REG[%d] = ", iReg);
  memTracePrint(p);



  printf("\n");
  sqlite3VdbeCheckMemInvariants(p);
}
#endif













#ifdef SQLITE_DEBUG
#  define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M)
#else
#  define REGISTER_TRACE(R,M)
#endif








>
|
>
|
|




|

>
>
>




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







85279
85280
85281
85282
85283
85284
85285
85286
85287
85288
85289
85290
85291
85292
85293
85294
85295
85296
85297
85298
85299
85300
85301
85302
85303
85304
85305
85306
85307
85308
85309
85310
85311
85312
85313
85314
85315
85316
85317
85318
85319
85320
85321
85322
#ifndef SQLITE_OMIT_FLOATING_POINT
  }else if( p->flags & MEM_Real ){
    printf(" r:%.17g", p->u.r);
#endif
  }else if( sqlite3VdbeMemIsRowSet(p) ){
    printf(" (rowset)");
  }else{
    StrAccum acc;
    char zBuf[1000];
    sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
    sqlite3VdbeMemPrettyPrint(p, &acc);
    printf(" %s", sqlite3StrAccumFinish(&acc));
  }
  if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
}
static void registerTrace(int iReg, Mem *p){
  printf("R[%d] = ", iReg);
  memTracePrint(p);
  if( p->pScopyFrom ){
    printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg]));
  }
  printf("\n");
  sqlite3VdbeCheckMemInvariants(p);
}
#endif

#ifdef SQLITE_DEBUG
/*
** Show the values of all registers in the virtual machine.  Used for
** interactive debugging.
*/
SQLITE_PRIVATE void sqlite3VdbeRegisterDump(Vdbe *v){
  int i;
  for(i=1; i<v->nMem; i++) registerTrace(i, v->aMem+i);
}
#endif /* SQLITE_DEBUG */


#ifdef SQLITE_DEBUG
#  define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M)
#else
#  define REGISTER_TRACE(R,M)
#endif

84950
84951
84952
84953
84954
84955
84956
84957
84958
84959
84960
84961
84962
84963
84964
  }
  assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
  assert( p->bIsReader || p->readOnly!=0 );
  p->iCurrentTime = 0;
  assert( p->explain==0 );
  p->pResultSet = 0;
  db->busyHandler.nBusy = 0;
  if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
  sqlite3VdbeIOTraceSql(p);
#ifdef SQLITE_DEBUG
  sqlite3BeginBenignMalloc();
  if( p->pc==0
   && (p->db->flags & (SQLITE_VdbeListing|SQLITE_VdbeEQP|SQLITE_VdbeTrace))!=0
  ){
    int i;







|







85516
85517
85518
85519
85520
85521
85522
85523
85524
85525
85526
85527
85528
85529
85530
  }
  assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
  assert( p->bIsReader || p->readOnly!=0 );
  p->iCurrentTime = 0;
  assert( p->explain==0 );
  p->pResultSet = 0;
  db->busyHandler.nBusy = 0;
  if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt;
  sqlite3VdbeIOTraceSql(p);
#ifdef SQLITE_DEBUG
  sqlite3BeginBenignMalloc();
  if( p->pc==0
   && (p->db->flags & (SQLITE_VdbeListing|SQLITE_VdbeEQP|SQLITE_VdbeTrace))!=0
  ){
    int i;
84998
84999
85000
85001
85002
85003
85004

85005
85006
85007
85008
85009
85010
85011
#endif

    /* Only allow tracing if SQLITE_DEBUG is defined.
    */
#ifdef SQLITE_DEBUG
    if( db->flags & SQLITE_VdbeTrace ){
      sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp);

    }
#endif
      

    /* Check to see if we need to simulate an interrupt.  This only happens
    ** if we have a special test build.
    */







>







85564
85565
85566
85567
85568
85569
85570
85571
85572
85573
85574
85575
85576
85577
85578
#endif

    /* Only allow tracing if SQLITE_DEBUG is defined.
    */
#ifdef SQLITE_DEBUG
    if( db->flags & SQLITE_VdbeTrace ){
      sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp);
      test_trace_breakpoint((int)(pOp - aOp),pOp,p);
    }
#endif
      

    /* Check to see if we need to simulate an interrupt.  This only happens
    ** if we have a special test build.
    */
85105
85106
85107
85108
85109
85110
85111














85112
85113
85114
85115
85116
85117
85118
85119
85120
85121
85122
85123
85124
85125
85126
85127
85128
85129
85130
85131
85132
85133
**
** The P1 parameter is not actually used by this opcode.  However, it
** is sometimes set to 1 instead of 0 as a hint to the command-line shell
** that this Goto is the bottom of a loop and that the lines from P2 down
** to the current line should be indented for EXPLAIN output.
*/
case OP_Goto: {             /* jump */














jump_to_p2_and_check_for_interrupt:
  pOp = &aOp[pOp->p2 - 1];

  /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
  ** OP_VNext, or OP_SorterNext) all jump here upon
  ** completion.  Check to see if sqlite3_interrupt() has been called
  ** or if the progress callback needs to be invoked. 
  **
  ** This code uses unstructured "goto" statements and does not look clean.
  ** But that is not due to sloppy coding habits. The code is written this
  ** way for performance, to avoid having to run the interrupt and progress
  ** checks on every opcode.  This helps sqlite3_step() to run about 1.5%
  ** faster according to "valgrind --tool=cachegrind" */
check_for_interrupt:
  if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
  /* Call the progress callback if it is configured and the required number
  ** of VDBE ops have been executed (either since this invocation of
  ** sqlite3VdbeExec() or since last time the progress callback was called).
  ** If the progress callback returns non-zero, exit the virtual machine with
  ** a return code SQLITE_ABORT.
  */







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














|







85672
85673
85674
85675
85676
85677
85678
85679
85680
85681
85682
85683
85684
85685
85686
85687
85688
85689
85690
85691
85692
85693
85694
85695
85696
85697
85698
85699
85700
85701
85702
85703
85704
85705
85706
85707
85708
85709
85710
85711
85712
85713
85714
**
** The P1 parameter is not actually used by this opcode.  However, it
** is sometimes set to 1 instead of 0 as a hint to the command-line shell
** that this Goto is the bottom of a loop and that the lines from P2 down
** to the current line should be indented for EXPLAIN output.
*/
case OP_Goto: {             /* jump */

#ifdef SQLITE_DEBUG
  /* In debuggging mode, when the p5 flags is set on an OP_Goto, that
  ** means we should really jump back to the preceeding OP_ReleaseReg
  ** instruction. */
  if( pOp->p5 ){
    assert( pOp->p2 < (int)(pOp - aOp) );
    assert( pOp->p2 > 1 );
    pOp = &aOp[pOp->p2 - 2];
    assert( pOp[1].opcode==OP_ReleaseReg );
    goto check_for_interrupt;
  }
#endif

jump_to_p2_and_check_for_interrupt:
  pOp = &aOp[pOp->p2 - 1];

  /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
  ** OP_VNext, or OP_SorterNext) all jump here upon
  ** completion.  Check to see if sqlite3_interrupt() has been called
  ** or if the progress callback needs to be invoked. 
  **
  ** This code uses unstructured "goto" statements and does not look clean.
  ** But that is not due to sloppy coding habits. The code is written this
  ** way for performance, to avoid having to run the interrupt and progress
  ** checks on every opcode.  This helps sqlite3_step() to run about 1.5%
  ** faster according to "valgrind --tool=cachegrind" */
check_for_interrupt:
  if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt;
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
  /* Call the progress callback if it is configured and the required number
  ** of VDBE ops have been executed (either since this invocation of
  ** sqlite3VdbeExec() or since last time the progress callback was called).
  ** If the progress callback returns non-zero, exit the virtual machine with
  ** a return code SQLITE_ABORT.
  */
85581
85582
85583
85584
85585
85586
85587
85588



85589


85590
85591
85592
85593
85594
85595
85596
  do{
    assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] );
    assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] );
    assert( memIsValid(pIn1) );
    memAboutToChange(p, pOut);
    sqlite3VdbeMemMove(pOut, pIn1);
#ifdef SQLITE_DEBUG
    if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<pOut ){



      pOut->pScopyFrom += pOp->p2 - p1;


    }
#endif
    Deephemeralize(pOut);
    REGISTER_TRACE(p2++, pOut);
    pIn1++;
    pOut++;
  }while( --n );







|
>
>
>
|
>
>







86162
86163
86164
86165
86166
86167
86168
86169
86170
86171
86172
86173
86174
86175
86176
86177
86178
86179
86180
86181
86182
  do{
    assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] );
    assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] );
    assert( memIsValid(pIn1) );
    memAboutToChange(p, pOut);
    sqlite3VdbeMemMove(pOut, pIn1);
#ifdef SQLITE_DEBUG
    pIn1->pScopyFrom = 0;
    { int i;
      for(i=1; i<p->nMem; i++){
        if( aMem[i].pScopyFrom==pIn1 ){
          aMem[i].pScopyFrom = pOut;
        }
      }
    }
#endif
    Deephemeralize(pOut);
    REGISTER_TRACE(p2++, pOut);
    pIn1++;
    pOut++;
  }while( --n );
85723
85724
85725
85726
85727
85728
85729








85730
85731
85732
85733
85734
85735

85736
85737
85738
85739
85740
85741
85742
  for(i=0; i<pOp->p2; i++){
    assert( memIsValid(&pMem[i]) );
    Deephemeralize(&pMem[i]);
    assert( (pMem[i].flags & MEM_Ephem)==0
            || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
    sqlite3VdbeMemNulTerminate(&pMem[i]);
    REGISTER_TRACE(pOp->p1+i, &pMem[i]);








  }
  if( db->mallocFailed ) goto no_mem;

  if( db->mTrace & SQLITE_TRACE_ROW ){
    db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
  }


  /* Return SQLITE_ROW
  */
  p->pc = (int)(pOp - aOp) + 1;
  rc = SQLITE_ROW;
  goto vdbe_return;
}







>
>
>
>
>
>
>
>






>







86309
86310
86311
86312
86313
86314
86315
86316
86317
86318
86319
86320
86321
86322
86323
86324
86325
86326
86327
86328
86329
86330
86331
86332
86333
86334
86335
86336
86337
  for(i=0; i<pOp->p2; i++){
    assert( memIsValid(&pMem[i]) );
    Deephemeralize(&pMem[i]);
    assert( (pMem[i].flags & MEM_Ephem)==0
            || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
    sqlite3VdbeMemNulTerminate(&pMem[i]);
    REGISTER_TRACE(pOp->p1+i, &pMem[i]);
#ifdef SQLITE_DEBUG
    /* The registers in the result will not be used again when the
    ** prepared statement restarts.  This is because sqlite3_column()
    ** APIs might have caused type conversions of made other changes to
    ** the register values.  Therefore, we can go ahead and break any
    ** OP_SCopy dependencies. */
    pMem[i].pScopyFrom = 0;
#endif
  }
  if( db->mallocFailed ) goto no_mem;

  if( db->mTrace & SQLITE_TRACE_ROW ){
    db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
  }


  /* Return SQLITE_ROW
  */
  p->pc = (int)(pOp - aOp) + 1;
  rc = SQLITE_ROW;
  goto vdbe_return;
}
85758
85759
85760
85761
85762
85763
85764
85765
85766
85767
85768
85769
85770
85771
85772
  i64 nByte;          /* Total size of the output string or blob */
  u16 flags1;         /* Initial flags for P1 */
  u16 flags2;         /* Initial flags for P2 */

  pIn1 = &aMem[pOp->p1];
  pIn2 = &aMem[pOp->p2];
  pOut = &aMem[pOp->p3];
  testcase( pIn1==pIn2 );
  testcase( pOut==pIn2 );
  assert( pIn1!=pOut );
  flags1 = pIn1->flags;
  testcase( flags1 & MEM_Null );
  testcase( pIn2->flags & MEM_Null );
  if( (flags1 | pIn2->flags) & MEM_Null ){
    sqlite3VdbeMemSetNull(pOut);







<







86353
86354
86355
86356
86357
86358
86359

86360
86361
86362
86363
86364
86365
86366
  i64 nByte;          /* Total size of the output string or blob */
  u16 flags1;         /* Initial flags for P1 */
  u16 flags2;         /* Initial flags for P2 */

  pIn1 = &aMem[pOp->p1];
  pIn2 = &aMem[pOp->p2];
  pOut = &aMem[pOp->p3];

  testcase( pOut==pIn2 );
  assert( pIn1!=pOut );
  flags1 = pIn1->flags;
  testcase( flags1 & MEM_Null );
  testcase( pIn2->flags & MEM_Null );
  if( (flags1 | pIn2->flags) & MEM_Null ){
    sqlite3VdbeMemSetNull(pOut);
86126
86127
86128
86129
86130
86131
86132

86133
86134
86135


86136
86137
86138
86139
86140
86141
86142
  testcase( pOp->p2==SQLITE_AFF_BLOB );
  testcase( pOp->p2==SQLITE_AFF_NUMERIC );
  testcase( pOp->p2==SQLITE_AFF_INTEGER );
  testcase( pOp->p2==SQLITE_AFF_REAL );
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  rc = ExpandBlob(pIn1);

  sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
  UPDATE_MAX_BLOBSIZE(pIn1);
  if( rc ) goto abort_due_to_error;


  break;
}
#endif /* SQLITE_OMIT_CAST */

/* Opcode: Eq P1 P2 P3 P4 P5
** Synopsis: IF r[P3]==r[P1]
**







>
|
<

>
>







86720
86721
86722
86723
86724
86725
86726
86727
86728

86729
86730
86731
86732
86733
86734
86735
86736
86737
86738
  testcase( pOp->p2==SQLITE_AFF_BLOB );
  testcase( pOp->p2==SQLITE_AFF_NUMERIC );
  testcase( pOp->p2==SQLITE_AFF_INTEGER );
  testcase( pOp->p2==SQLITE_AFF_REAL );
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  rc = ExpandBlob(pIn1);
  if( rc ) goto abort_due_to_error;
  rc = sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);

  if( rc ) goto abort_due_to_error;
  UPDATE_MAX_BLOBSIZE(pIn1);
  REGISTER_TRACE(pOp->p1, pIn1);
  break;
}
#endif /* SQLITE_OMIT_CAST */

/* Opcode: Eq P1 P2 P3 P4 P5
** Synopsis: IF r[P3]==r[P1]
**
86288
86289
86290
86291
86292
86293
86294
86295
86296
86297
86298
86299
86300
86301
86302
86303
86304
86305
86306
    /* Neither operand is NULL.  Do a comparison. */
    affinity = pOp->p5 & SQLITE_AFF_MASK;
    if( affinity>=SQLITE_AFF_NUMERIC ){
      if( (flags1 | flags3)&MEM_Str ){
        if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
          applyNumericAffinity(pIn1,0);
          assert( flags3==pIn3->flags );
          /* testcase( flags3!=pIn3->flags );
          ** this used to be possible with pIn1==pIn3, but not since
          ** the column cache was removed.  The following assignment
          ** is essentially a no-op.  But, it provides defense-in-depth
          ** in case our analysis is incorrect, so it is left in. */
          flags3 = pIn3->flags;
        }
        if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
          applyNumericAffinity(pIn3,0);
        }
      }
      /* Handle the common case of integer comparison here, as an







<
<
<
<
<







86884
86885
86886
86887
86888
86889
86890





86891
86892
86893
86894
86895
86896
86897
    /* Neither operand is NULL.  Do a comparison. */
    affinity = pOp->p5 & SQLITE_AFF_MASK;
    if( affinity>=SQLITE_AFF_NUMERIC ){
      if( (flags1 | flags3)&MEM_Str ){
        if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
          applyNumericAffinity(pIn1,0);
          assert( flags3==pIn3->flags );





          flags3 = pIn3->flags;
        }
        if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
          applyNumericAffinity(pIn3,0);
        }
      }
      /* Handle the common case of integer comparison here, as an
86315
86316
86317
86318
86319
86320
86321
86322
86323
86324
86325
86326
86327
86328
86329
      if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
        testcase( pIn1->flags & MEM_Int );
        testcase( pIn1->flags & MEM_Real );
        testcase( pIn1->flags & MEM_IntReal );
        sqlite3VdbeMemStringify(pIn1, encoding, 1);
        testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
        flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
        assert( pIn1!=pIn3 );
      }
      if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
        testcase( pIn3->flags & MEM_Int );
        testcase( pIn3->flags & MEM_Real );
        testcase( pIn3->flags & MEM_IntReal );
        sqlite3VdbeMemStringify(pIn3, encoding, 1);
        testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) );







|







86906
86907
86908
86909
86910
86911
86912
86913
86914
86915
86916
86917
86918
86919
86920
      if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
        testcase( pIn1->flags & MEM_Int );
        testcase( pIn1->flags & MEM_Real );
        testcase( pIn1->flags & MEM_IntReal );
        sqlite3VdbeMemStringify(pIn1, encoding, 1);
        testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
        flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
        if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
      }
      if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
        testcase( pIn3->flags & MEM_Int );
        testcase( pIn3->flags & MEM_Real );
        testcase( pIn3->flags & MEM_IntReal );
        sqlite3VdbeMemStringify(pIn3, encoding, 1);
        testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) );
86350
86351
86352
86353
86354
86355
86356
86357
86358
86359
86360
86361
86362
86363
86364
86365
86366
86367
    res2 = aEQb[pOp->opcode - OP_Ne];
  }else{
    static const unsigned char aGTb[] = { 1,  0,  1,  0,  0,  1 };
    res2 = aGTb[pOp->opcode - OP_Ne];
  }

  /* Undo any changes made by applyAffinity() to the input registers. */
  assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
  pIn1->flags = flags1;
  assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
  pIn3->flags = flags3;

  if( pOp->p5 & SQLITE_STOREP2 ){
    pOut = &aMem[pOp->p2];
    iCompare = res;
    if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
      /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
      ** and prevents OP_Ne from overwriting NULL with 0.  This flag







|
|
|
|







86941
86942
86943
86944
86945
86946
86947
86948
86949
86950
86951
86952
86953
86954
86955
86956
86957
86958
    res2 = aEQb[pOp->opcode - OP_Ne];
  }else{
    static const unsigned char aGTb[] = { 1,  0,  1,  0,  0,  1 };
    res2 = aGTb[pOp->opcode - OP_Ne];
  }

  /* Undo any changes made by applyAffinity() to the input registers. */
  assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
  pIn3->flags = flags3;
  assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
  pIn1->flags = flags1;

  if( pOp->p5 & SQLITE_STOREP2 ){
    pOut = &aMem[pOp->p2];
    iCompare = res;
    if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
      /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
      ** and prevents OP_Ne from overwriting NULL with 0.  This flag
86389
86390
86391
86392
86393
86394
86395
86396





86397
86398
86399
86400
86401
86402
86403







86404
86405



86406
86407
86408
86409
86410
86411
86412
    }
  }
  break;
}

/* Opcode: ElseNotEq * P2 * * *
**
** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator.





** If result of an OP_Eq comparison on the same two operands
** would have be NULL or false (0), then then jump to P2. 
** If the result of an OP_Eq comparison on the two previous operands
** would have been true (1), then fall through.
*/
case OP_ElseNotEq: {       /* same as TK_ESCAPE, jump */
  assert( pOp>aOp );







  assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt );
  assert( pOp[-1].p5 & SQLITE_STOREP2 );



  VdbeBranchTaken(iCompare!=0, 2);
  if( iCompare!=0 ) goto jump_to_p2;
  break;
}


/* Opcode: Permutation * * * P4 *







|
>
>
>
>
>
|
|
|
|


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







86980
86981
86982
86983
86984
86985
86986
86987
86988
86989
86990
86991
86992
86993
86994
86995
86996
86997
86998
86999
87000
87001
87002
87003
87004
87005
87006
87007
87008
87009
87010
87011
87012
87013
87014
87015
87016
87017
87018
    }
  }
  break;
}

/* Opcode: ElseNotEq * P2 * * *
**
** This opcode must follow an OP_Lt or OP_Gt comparison operator.  There
** can be zero or more OP_ReleaseReg opcodes intervening, but no other
** opcodes are allowed to occur between this instruction and the previous
** OP_Lt or OP_Gt.  Furthermore, the prior OP_Lt or OP_Gt must have the
** SQLITE_STOREP2 bit set in the P5 field.
**
** If result of an OP_Eq comparison on the same two operands as the
** prior OP_Lt or OP_Gt would have been NULL or false (0), then then
** jump to P2.  If the result of an OP_Eq comparison on the two previous
** operands would have been true (1), then fall through.
*/
case OP_ElseNotEq: {       /* same as TK_ESCAPE, jump */

#ifdef SQLITE_DEBUG
  /* Verify the preconditions of this opcode - that it follows an OP_Lt or
  ** OP_Gt with the SQLITE_STOREP2 flag set, with zero or more intervening
  ** OP_ReleaseReg opcodes */
  int iAddr;
  for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){
    if( aOp[iAddr].opcode==OP_ReleaseReg ) continue;
    assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt );
    assert( aOp[iAddr].p5 & SQLITE_STOREP2 );
    break;
  }
#endif /* SQLITE_DEBUG */
  VdbeBranchTaken(iCompare!=0, 2);
  if( iCompare!=0 ) goto jump_to_p2;
  break;
}


/* Opcode: Permutation * * * P4 *
86809
86810
86811
86812
86813
86814
86815

86816

86817
86818
86819
86820
86821
86822
86823
86824
86825
86826
86827
86828
86829
86830
86831
86832
86833
86834
86835
  const u8 *zData;   /* Part of the record being decoded */
  const u8 *zHdr;    /* Next unparsed byte of the header */
  const u8 *zEndHdr; /* Pointer to first byte after the header */
  u64 offset64;      /* 64-bit offset */
  u32 t;             /* A type code from the record header */
  Mem *pReg;         /* PseudoTable input register */


  pC = p->apCsr[pOp->p1];

  p2 = pOp->p2;

  /* If the cursor cache is stale (meaning it is not currently point at
  ** the correct row) then bring it up-to-date by doing the necessary 
  ** B-Tree seek. */
  rc = sqlite3VdbeCursorMoveto(&pC, &p2);
  if( rc ) goto abort_due_to_error;

  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
  pDest = &aMem[pOp->p3];
  memAboutToChange(p, pDest);
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pC!=0 );
  assert( p2<pC->nField );
  aOffset = pC->aOffset;
  assert( pC->eCurType!=CURTYPE_VTAB );
  assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
  assert( pC->eCurType!=CURTYPE_SORTER );








>

>











<







87415
87416
87417
87418
87419
87420
87421
87422
87423
87424
87425
87426
87427
87428
87429
87430
87431
87432
87433
87434
87435

87436
87437
87438
87439
87440
87441
87442
  const u8 *zData;   /* Part of the record being decoded */
  const u8 *zHdr;    /* Next unparsed byte of the header */
  const u8 *zEndHdr; /* Pointer to first byte after the header */
  u64 offset64;      /* 64-bit offset */
  u32 t;             /* A type code from the record header */
  Mem *pReg;         /* PseudoTable input register */

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  p2 = pOp->p2;

  /* If the cursor cache is stale (meaning it is not currently point at
  ** the correct row) then bring it up-to-date by doing the necessary 
  ** B-Tree seek. */
  rc = sqlite3VdbeCursorMoveto(&pC, &p2);
  if( rc ) goto abort_due_to_error;

  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
  pDest = &aMem[pOp->p3];
  memAboutToChange(p, pDest);

  assert( pC!=0 );
  assert( p2<pC->nField );
  aOffset = pC->aOffset;
  assert( pC->eCurType!=CURTYPE_VTAB );
  assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
  assert( pC->eCurType!=CURTYPE_SORTER );

86914
86915
86916
86917
86918
86919
86920
86921
86922
86923
86924
86925
86926
86927
86928
    /* If there is more header available for parsing in the record, try
    ** to extract additional fields up through the p2+1-th field 
    */
    if( pC->iHdrOffset<aOffset[0] ){
      /* Make sure zData points to enough of the record to cover the header. */
      if( pC->aRow==0 ){
        memset(&sMem, 0, sizeof(sMem));
        rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, aOffset[0], &sMem);
        if( rc!=SQLITE_OK ) goto abort_due_to_error;
        zData = (u8*)sMem.z;
      }else{
        zData = pC->aRow;
      }
  
      /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */







|







87521
87522
87523
87524
87525
87526
87527
87528
87529
87530
87531
87532
87533
87534
87535
    /* If there is more header available for parsing in the record, try
    ** to extract additional fields up through the p2+1-th field 
    */
    if( pC->iHdrOffset<aOffset[0] ){
      /* Make sure zData points to enough of the record to cover the header. */
      if( pC->aRow==0 ){
        memset(&sMem, 0, sizeof(sMem));
        rc = sqlite3VdbeMemFromBtreeZeroOffset(pC->uc.pCursor,aOffset[0],&sMem);
        if( rc!=SQLITE_OK ) goto abort_due_to_error;
        zData = (u8*)sMem.z;
      }else{
        zData = pC->aRow;
      }
  
      /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
87032
87033
87034
87035
87036
87037
87038

87039

87040
87041
87042
87043
87044
87045
87046
87047
87048
87049
      **    2. the length(X) function if X is a blob, and
      **    3. if the content length is zero.
      ** So we might as well use bogus content rather than reading
      ** content from disk. 
      **
      ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
      ** buffer passed to it, debugging function VdbeMemPrettyPrint() may

      ** read up to 16. So 16 bytes of bogus content is supplied.

      */
      static u8 aZero[16];  /* This is the bogus content */
      sqlite3VdbeSerialGet(aZero, t, pDest);
    }else{
      rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
      if( rc!=SQLITE_OK ) goto abort_due_to_error;
      sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
      pDest->flags &= ~MEM_Ephem;
    }
  }







>
|
>

<
|







87639
87640
87641
87642
87643
87644
87645
87646
87647
87648
87649

87650
87651
87652
87653
87654
87655
87656
87657
      **    2. the length(X) function if X is a blob, and
      **    3. if the content length is zero.
      ** So we might as well use bogus content rather than reading
      ** content from disk. 
      **
      ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
      ** buffer passed to it, debugging function VdbeMemPrettyPrint() may
      ** read more.  Use the global constant sqlite3CtypeMap[] as the array,
      ** as that array is 256 bytes long (plenty for VdbeMemPrettyPrint())
      ** and it begins with a bunch of zeros.
      */

      sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest);
    }else{
      rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
      if( rc!=SQLITE_OK ) goto abort_due_to_error;
      sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
      pDest->flags &= ~MEM_Ephem;
    }
  }
87078
87079
87080
87081
87082
87083
87084
87085
87086
87087
87088
87089
87090
87091
87092
  zAffinity = pOp->p4.z;
  assert( zAffinity!=0 );
  assert( pOp->p2>0 );
  assert( zAffinity[pOp->p2]==0 );
  pIn1 = &aMem[pOp->p1];
  while( 1 /*exit-by-break*/ ){
    assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
    assert( memIsValid(pIn1) );
    applyAffinity(pIn1, zAffinity[0], encoding);
    if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){
      /* When applying REAL affinity, if the result is still an MEM_Int
      ** that will fit in 6 bytes, then change the type to MEM_IntReal
      ** so that we keep the high-resolution integer value but know that
      ** the type really wants to be REAL. */
      testcase( pIn1->u.i==140737488355328LL );







|







87686
87687
87688
87689
87690
87691
87692
87693
87694
87695
87696
87697
87698
87699
87700
  zAffinity = pOp->p4.z;
  assert( zAffinity!=0 );
  assert( pOp->p2>0 );
  assert( zAffinity[pOp->p2]==0 );
  pIn1 = &aMem[pOp->p1];
  while( 1 /*exit-by-break*/ ){
    assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
    assert( zAffinity[0]==SQLITE_AFF_NONE || memIsValid(pIn1) );
    applyAffinity(pIn1, zAffinity[0], encoding);
    if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){
      /* When applying REAL affinity, if the result is still an MEM_Int
      ** that will fit in 6 bytes, then change the type to MEM_IntReal
      ** so that we keep the high-resolution integer value but know that
      ** the type really wants to be REAL. */
      testcase( pIn1->u.i==140737488355328LL );
87524
87525
87526
87527
87528
87529
87530
87531
87532





87533
87534
87535
87536
87537
87538
87539
        db->autoCommit = 1;
        if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
          p->pc = (int)(pOp - aOp);
          db->autoCommit = 0;
          p->rc = rc = SQLITE_BUSY;
          goto vdbe_return;
        }
        db->isTransactionSavepoint = 0;
        rc = p->rc;





      }else{
        int isSchemaChange;
        iSavepoint = db->nSavepoint - iSavepoint - 1;
        if( p1==SAVEPOINT_ROLLBACK ){
          isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0;
          for(ii=0; ii<db->nDb; ii++){
            rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,







<

>
>
>
>
>







88132
88133
88134
88135
88136
88137
88138

88139
88140
88141
88142
88143
88144
88145
88146
88147
88148
88149
88150
88151
        db->autoCommit = 1;
        if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
          p->pc = (int)(pOp - aOp);
          db->autoCommit = 0;
          p->rc = rc = SQLITE_BUSY;
          goto vdbe_return;
        }

        rc = p->rc;
        if( rc ){
          db->autoCommit = 0;
        }else{
          db->isTransactionSavepoint = 0;
        }
      }else{
        int isSchemaChange;
        iSavepoint = db->nSavepoint - iSavepoint - 1;
        if( p1==SAVEPOINT_ROLLBACK ){
          isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0;
          for(ii=0; ii<db->nDb; ii++){
            rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
87553
87554
87555
87556
87557
87558
87559

87560
87561
87562
87563
87564
87565
87566
        }
        if( isSchemaChange ){
          sqlite3ExpirePreparedStatements(db, 0);
          sqlite3ResetAllSchemasOfConnection(db);
          db->mDbFlags |= DBFLAG_SchemaChange;
        }
      }

  
      /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all 
      ** savepoints nested inside of the savepoint being operated on. */
      while( db->pSavepoint!=pSavepoint ){
        pTmp = db->pSavepoint;
        db->pSavepoint = pTmp->pNext;
        sqlite3DbFree(db, pTmp);







>







88165
88166
88167
88168
88169
88170
88171
88172
88173
88174
88175
88176
88177
88178
88179
        }
        if( isSchemaChange ){
          sqlite3ExpirePreparedStatements(db, 0);
          sqlite3ResetAllSchemasOfConnection(db);
          db->mDbFlags |= DBFLAG_SchemaChange;
        }
      }
      if( rc ) goto abort_due_to_error;
  
      /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all 
      ** savepoints nested inside of the savepoint being operated on. */
      while( db->pSavepoint!=pSavepoint ){
        pTmp = db->pSavepoint;
        db->pSavepoint = pTmp->pNext;
        sqlite3DbFree(db, pTmp);
87860
87861
87862
87863
87864
87865
87866
87867
87868
87869
87870
87871
87872
87873
87874
** values need not be contiguous but all P1 values should be small integers.
** It is an error for P1 to be negative.
**
** Allowed P5 bits:
** <ul>
** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
**       of OP_SeekLE/OP_IdxGT)
** </ul>
**
** The P4 value may be either an integer (P4_INT32) or a pointer to
** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo 
** object, then table being opened must be an [index b-tree] where the
** KeyInfo object defines the content and collating 
** sequence of that index b-tree. Otherwise, if P4 is an integer 







|







88473
88474
88475
88476
88477
88478
88479
88480
88481
88482
88483
88484
88485
88486
88487
** values need not be contiguous but all P1 values should be small integers.
** It is an error for P1 to be negative.
**
** Allowed P5 bits:
** <ul>
** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
**       of OP_SeekLE/OP_IdxLT)
** </ul>
**
** The P4 value may be either an integer (P4_INT32) or a pointer to
** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo 
** object, then table being opened must be an [index b-tree] where the
** KeyInfo object defines the content and collating 
** sequence of that index b-tree. Otherwise, if P4 is an integer 
87890
87891
87892
87893
87894
87895
87896
87897
87898
87899
87900
87901
87902
87903
87904
** be the same as every other ReopenIdx or OpenRead for the same cursor
** number.
**
** Allowed P5 bits:
** <ul>
** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
**       of OP_SeekLE/OP_IdxGT)
** </ul>
**
** See also: OP_OpenRead, OP_OpenWrite
*/
/* Opcode: OpenWrite P1 P2 P3 P4 P5
** Synopsis: root=P2 iDb=P3
**







|







88503
88504
88505
88506
88507
88508
88509
88510
88511
88512
88513
88514
88515
88516
88517
** be the same as every other ReopenIdx or OpenRead for the same cursor
** number.
**
** Allowed P5 bits:
** <ul>
** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
**       of OP_SeekLE/OP_IdxLT)
** </ul>
**
** See also: OP_OpenRead, OP_OpenWrite
*/
/* Opcode: OpenWrite P1 P2 P3 P4 P5
** Synopsis: root=P2 iDb=P3
**
87914
87915
87916
87917
87918
87919
87920
87921
87922
87923
87924
87925
87926
87927
87928
** value, then the table being opened must be a [table b-tree] with a
** number of columns no less than the value of P4.
**
** Allowed P5 bits:
** <ul>
** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
**       of OP_SeekLE/OP_IdxGT)
** <li>  <b>0x08 OPFLAG_FORDELETE</b>: This cursor is used only to seek
**       and subsequently delete entries in an index btree.  This is a
**       hint to the storage engine that the storage engine is allowed to
**       ignore.  The hint is not used by the official SQLite b*tree storage
**       engine, but is used by COMDB2.
** <li>  <b>0x10 OPFLAG_P2ISREG</b>: Use the content of register P2
**       as the root page, not the value of P2 itself.







|







88527
88528
88529
88530
88531
88532
88533
88534
88535
88536
88537
88538
88539
88540
88541
** value, then the table being opened must be a [table b-tree] with a
** number of columns no less than the value of P4.
**
** Allowed P5 bits:
** <ul>
** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
**       of OP_SeekLE/OP_IdxLT)
** <li>  <b>0x08 OPFLAG_FORDELETE</b>: This cursor is used only to seek
**       and subsequently delete entries in an index btree.  This is a
**       hint to the storage engine that the storage engine is allowed to
**       ignore.  The hint is not used by the official SQLite b*tree storage
**       engine, but is used by COMDB2.
** <li>  <b>0x10 OPFLAG_P2ISREG</b>: Use the content of register P2
**       as the root page, not the value of P2 itself.
88026
88027
88028
88029
88030
88031
88032
88033
88034
88035
88036
88037
88038
88039
88040
88041
88042
88043
88044
88045
88046
88047
88048
88049
88050
88051
88052
88053
88054

88055
88056
88057
88058
88059
88060
88061
  ** since moved into the btree layer.  */  
  pCur->isTable = pOp->p4type!=P4_KEYINFO;

open_cursor_set_hints:
  assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
  assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
  testcase( pOp->p5 & OPFLAG_BULKCSR );
#ifdef SQLITE_ENABLE_CURSOR_HINTS
  testcase( pOp->p2 & OPFLAG_SEEKEQ );
#endif
  sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
                               (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
  if( rc ) goto abort_due_to_error;
  break;
}

/* Opcode: OpenDup P1 P2 * * *
**
** Open a new cursor P1 that points to the same ephemeral table as
** cursor P2.  The P2 cursor must have been opened by a prior OP_OpenEphemeral
** opcode.  Only ephemeral cursors may be duplicated.
**
** Duplicate ephemeral cursors are used for self-joins of materialized views.
*/
case OP_OpenDup: {
  VdbeCursor *pOrig;    /* The original cursor to be duplicated */
  VdbeCursor *pCx;      /* The new cursor */

  pOrig = p->apCsr[pOp->p2];

  assert( pOrig->pBtx!=0 );  /* Only ephemeral cursors can be duplicated */

  pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
  if( pCx==0 ) goto no_mem;
  pCx->nullRow = 1;
  pCx->isEphemeral = 1;
  pCx->pKeyInfo = pOrig->pKeyInfo;







<

<



















>







88639
88640
88641
88642
88643
88644
88645

88646

88647
88648
88649
88650
88651
88652
88653
88654
88655
88656
88657
88658
88659
88660
88661
88662
88663
88664
88665
88666
88667
88668
88669
88670
88671
88672
88673
  ** since moved into the btree layer.  */  
  pCur->isTable = pOp->p4type!=P4_KEYINFO;

open_cursor_set_hints:
  assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
  assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
  testcase( pOp->p5 & OPFLAG_BULKCSR );

  testcase( pOp->p2 & OPFLAG_SEEKEQ );

  sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
                               (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
  if( rc ) goto abort_due_to_error;
  break;
}

/* Opcode: OpenDup P1 P2 * * *
**
** Open a new cursor P1 that points to the same ephemeral table as
** cursor P2.  The P2 cursor must have been opened by a prior OP_OpenEphemeral
** opcode.  Only ephemeral cursors may be duplicated.
**
** Duplicate ephemeral cursors are used for self-joins of materialized views.
*/
case OP_OpenDup: {
  VdbeCursor *pOrig;    /* The original cursor to be duplicated */
  VdbeCursor *pCx;      /* The new cursor */

  pOrig = p->apCsr[pOp->p2];
  assert( pOrig );
  assert( pOrig->pBtx!=0 );  /* Only ephemeral cursors can be duplicated */

  pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
  if( pCx==0 ) goto no_mem;
  pCx->nullRow = 1;
  pCx->isEphemeral = 1;
  pCx->pKeyInfo = pOrig->pKeyInfo;
88111
88112
88113
88114
88115
88116
88117
88118
88119
88120
88121
88122
88123
88124
88125
88126
88127
88128
88129
88130
88131
88132
88133
      SQLITE_OPEN_CREATE |
      SQLITE_OPEN_EXCLUSIVE |
      SQLITE_OPEN_DELETEONCLOSE |
      SQLITE_OPEN_TRANSIENT_DB;
  assert( pOp->p1>=0 );
  assert( pOp->p2>=0 );
  pCx = p->apCsr[pOp->p1];
  if( pCx ){
    /* If the ephermeral table is already open, erase all existing content
    ** so that the table is empty again, rather than creating a new table. */
    assert( pCx->isEphemeral );
    pCx->seqCount = 0;
    pCx->cacheStatus = CACHE_STALE;
    if( pCx->pBtx ){
      rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0);
    }
  }else{
    pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
    if( pCx==0 ) goto no_mem;
    pCx->isEphemeral = 1;
    rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, 
                          BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
                          vfsFlags);







|





<
|
<







88723
88724
88725
88726
88727
88728
88729
88730
88731
88732
88733
88734
88735

88736

88737
88738
88739
88740
88741
88742
88743
      SQLITE_OPEN_CREATE |
      SQLITE_OPEN_EXCLUSIVE |
      SQLITE_OPEN_DELETEONCLOSE |
      SQLITE_OPEN_TRANSIENT_DB;
  assert( pOp->p1>=0 );
  assert( pOp->p2>=0 );
  pCx = p->apCsr[pOp->p1];
  if( pCx && pCx->pBtx ){
    /* If the ephermeral table is already open, erase all existing content
    ** so that the table is empty again, rather than creating a new table. */
    assert( pCx->isEphemeral );
    pCx->seqCount = 0;
    pCx->cacheStatus = CACHE_STALE;

    rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0);

  }else{
    pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
    if( pCx==0 ) goto no_mem;
    pCx->isEphemeral = 1;
    rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, 
                          BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
                          vfsFlags);
88285
88286
88287
88288
88289
88290
88291
88292
88293
88294
88295
88296


88297
88298
88299
88300
88301
88302
88303
88304
88305
88306
88307
88308
88309
88310
88311
88312
88313
88314
88315
88316
88317
88318
88319
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that  it points to the smallest entry that 
** is greater than or equal to the key value. If there are no records 
** greater than or equal to the key and P2 is not zero, then jump to P2.
**
** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
** opcode will always land on a record that equally equals the key, or
** else jump immediately to P2.  When the cursor is OPFLAG_SEEKEQ, this
** opcode must be followed by an IdxLE opcode with the same arguments.
** The IdxLE opcode will be skipped if this opcode succeeds, but the
** IdxLE opcode will be used on subsequent loop iterations.


**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end.  In other words, the cursor is
** configured to use Next, not Prev.
**
** See also: Found, NotFound, SeekLt, SeekGt, SeekLe
*/
/* Opcode: SeekGT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that  it points to the smallest entry that 
** is greater than the key value. If there are no records greater than 
** the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end.  In other words, the cursor is
** configured to use Next, not Prev.
**







|
|
|
|
|
>
>















|







88895
88896
88897
88898
88899
88900
88901
88902
88903
88904
88905
88906
88907
88908
88909
88910
88911
88912
88913
88914
88915
88916
88917
88918
88919
88920
88921
88922
88923
88924
88925
88926
88927
88928
88929
88930
88931
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that  it points to the smallest entry that 
** is greater than or equal to the key value. If there are no records 
** greater than or equal to the key and P2 is not zero, then jump to P2.
**
** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
** opcode will either land on a record that exactly matches the key, or
** else it will cause a jump to P2.  When the cursor is OPFLAG_SEEKEQ,
** this opcode must be followed by an IdxLE opcode with the same arguments.
** The IdxGT opcode will be skipped if this opcode succeeds, but the
** IdxGT opcode will be used on subsequent loop iterations.  The 
** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this
** is an equality search.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end.  In other words, the cursor is
** configured to use Next, not Prev.
**
** See also: Found, NotFound, SeekLt, SeekGt, SeekLe
*/
/* Opcode: SeekGT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that it points to the smallest entry that 
** is greater than the key value. If there are no records greater than 
** the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end.  In other words, the cursor is
** configured to use Next, not Prev.
**
88350
88351
88352
88353
88354
88355
88356
88357
88358
88359
88360
88361


88362
88363
88364
88365
88366
88367
88368
** less than or equal to the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning.  In other words, the cursor is
** configured to use Prev, not Next.
**
** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
** opcode will always land on a record that equally equals the key, or
** else jump immediately to P2.  When the cursor is OPFLAG_SEEKEQ, this
** opcode must be followed by an IdxGE opcode with the same arguments.
** The IdxGE opcode will be skipped if this opcode succeeds, but the
** IdxGE opcode will be used on subsequent loop iterations.


**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
case OP_SeekLT:         /* jump, in3, group */
case OP_SeekLE:         /* jump, in3, group */
case OP_SeekGE:         /* jump, in3, group */
case OP_SeekGT: {       /* jump, in3, group */







|
|
|

|
>
>







88962
88963
88964
88965
88966
88967
88968
88969
88970
88971
88972
88973
88974
88975
88976
88977
88978
88979
88980
88981
88982
** less than or equal to the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning.  In other words, the cursor is
** configured to use Prev, not Next.
**
** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
** opcode will either land on a record that exactly matches the key, or
** else it will cause a jump to P2.  When the cursor is OPFLAG_SEEKEQ,
** this opcode must be followed by an IdxLE opcode with the same arguments.
** The IdxGE opcode will be skipped if this opcode succeeds, but the
** IdxGE opcode will be used on subsequent loop iterations.  The 
** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this
** is an equality search.
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
case OP_SeekLT:         /* jump, in3, group */
case OP_SeekLE:         /* jump, in3, group */
case OP_SeekGE:         /* jump, in3, group */
case OP_SeekGT: {       /* jump, in3, group */
88391
88392
88393
88394
88395
88396
88397
88398
88399
88400
88401
88402
88403
88404
88405
  pC->seekOp = pOp->opcode;
#endif

  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;
  if( pC->isTable ){
    u16 flags3, newType;
    /* The BTREE_SEEK_EQ flag is only set on index cursors */
    assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0
              || CORRUPT_DB );

    /* The input value in P3 might be of any type: integer, real, string,
    ** blob, or NULL.  But it needs to be an integer before we can do
    ** the seek, so convert it. */
    pIn3 = &aMem[pOp->p3];







|







89005
89006
89007
89008
89009
89010
89011
89012
89013
89014
89015
89016
89017
89018
89019
  pC->seekOp = pOp->opcode;
#endif

  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;
  if( pC->isTable ){
    u16 flags3, newType;
    /* The OPFLAG_SEEKEQ/BTREE_SEEK_EQ flag is only set on index cursors */
    assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0
              || CORRUPT_DB );

    /* The input value in P3 might be of any type: integer, real, string,
    ** blob, or NULL.  But it needs to be an integer before we can do
    ** the seek, so convert it. */
    pIn3 = &aMem[pOp->p3];
88450
88451
88452
88453
88454
88455
88456
88457
88458
88459

88460
88461
88462
88463
88464


88465
88466
88467
88468
88469
88470
88471
    }
    rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
    pC->movetoTarget = iKey;  /* Used by OP_Delete */
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }
  }else{
    /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
    ** OP_SeekLE opcodes are allowed, and these must be immediately followed
    ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.

    */
    if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){
      eqOnly = 1;
      assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
      assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );


      assert( pOp[1].p1==pOp[0].p1 );
      assert( pOp[1].p2==pOp[0].p2 );
      assert( pOp[1].p3==pOp[0].p3 );
      assert( pOp[1].p4.i==pOp[0].p4.i );
    }

    nField = pOp->p4.i;







|
|
|
>





>
>







89064
89065
89066
89067
89068
89069
89070
89071
89072
89073
89074
89075
89076
89077
89078
89079
89080
89081
89082
89083
89084
89085
89086
89087
89088
    }
    rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
    pC->movetoTarget = iKey;  /* Used by OP_Delete */
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }
  }else{
    /* For a cursor with the OPFLAG_SEEKEQ/BTREE_SEEK_EQ hint, only the
    ** OP_SeekGE and OP_SeekLE opcodes are allowed, and these must be
    ** immediately followed by an OP_IdxGT or OP_IdxLT opcode, respectively,
    ** with the same key.
    */
    if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){
      eqOnly = 1;
      assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
      assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
      assert( pOp->opcode==OP_SeekGE || pOp[1].opcode==OP_IdxLT );
      assert( pOp->opcode==OP_SeekLE || pOp[1].opcode==OP_IdxGT );
      assert( pOp[1].p1==pOp[0].p1 );
      assert( pOp[1].p2==pOp[0].p2 );
      assert( pOp[1].p3==pOp[0].p3 );
      assert( pOp[1].p4.i==pOp[0].p4.i );
    }

    nField = pOp->p4.i;
88551
88552
88553
88554
88555
88556
88557
88558
88559
88560
88561
88562
88563
88564
88565
88566
88567
88568
88569
88570
88571














88572
88573
88574
88575
88576
88577
88578
  break;
}

/* Opcode: SeekHit P1 P2 * * *
** Synopsis: seekHit=P2
**
** Set the seekHit flag on cursor P1 to the value in P2.
** The seekHit flag is used by the IfNoHope opcode.
**
** P1 must be a valid b-tree cursor.  P2 must be a boolean value,
** either 0 or 1.
*/
case OP_SeekHit: {
  VdbeCursor *pC;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pOp->p2==0 || pOp->p2==1 );
  pC->seekHit = pOp->p2 & 1;
  break;
}















/* Opcode: Found P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If P4==0 then register P3 holds a blob constructed by MakeRecord.  If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.







|













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







89168
89169
89170
89171
89172
89173
89174
89175
89176
89177
89178
89179
89180
89181
89182
89183
89184
89185
89186
89187
89188
89189
89190
89191
89192
89193
89194
89195
89196
89197
89198
89199
89200
89201
89202
89203
89204
89205
89206
89207
89208
89209
  break;
}

/* Opcode: SeekHit P1 P2 * * *
** Synopsis: seekHit=P2
**
** Set the seekHit flag on cursor P1 to the value in P2.
* The seekHit flag is used by the IfNoHope opcode.
**
** P1 must be a valid b-tree cursor.  P2 must be a boolean value,
** either 0 or 1.
*/
case OP_SeekHit: {
  VdbeCursor *pC;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pOp->p2==0 || pOp->p2==1 );
  pC->seekHit = pOp->p2 & 1;
  break;
}

/* Opcode: IfNotOpen P1 P2 * * *
** Synopsis: if( !csr[P1] ) goto P2
**
** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through.
*/
case OP_IfNotOpen: {        /* jump */
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2);
  if( !p->apCsr[pOp->p1] ){
    goto jump_to_p2_and_check_for_interrupt;
  }
  break;
}

/* Opcode: Found P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If P4==0 then register P3 holds a blob constructed by MakeRecord.  If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
89054
89055
89056
89057
89058
89059
89060

89061
89062
89063
89064
89065
89066
89067

  pData = &aMem[pOp->p2];
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( memIsValid(pData) );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->eCurType==CURTYPE_BTREE );

  assert( pC->uc.pCursor!=0 );
  assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
  assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
  REGISTER_TRACE(pOp->p2, pData);
  sqlite3VdbeIncrWriteCounter(p, pC);

  pKey = &aMem[pOp->p3];







>







89685
89686
89687
89688
89689
89690
89691
89692
89693
89694
89695
89696
89697
89698
89699

  pData = &aMem[pOp->p2];
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( memIsValid(pData) );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->eCurType==CURTYPE_BTREE );
  assert( pC->deferredMoveto==0 );
  assert( pC->uc.pCursor!=0 );
  assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
  assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
  REGISTER_TRACE(pOp->p2, pData);
  sqlite3VdbeIncrWriteCounter(p, pC);

  pKey = &aMem[pOp->p3];
89171
89172
89173
89174
89175
89176
89177
89178




89179
89180
89181
89182
89183
89184
89185
  assert( pC!=0 );
  assert( pC->eCurType==CURTYPE_BTREE );
  assert( pC->uc.pCursor!=0 );
  assert( pC->deferredMoveto==0 );
  sqlite3VdbeIncrWriteCounter(p, pC);

#ifdef SQLITE_DEBUG
  if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){




    /* If p5 is zero, the seek operation that positioned the cursor prior to
    ** OP_Delete will have also set the pC->movetoTarget field to the rowid of
    ** the row that is being deleted */
    i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    assert( CORRUPT_DB || pC->movetoTarget==iKey );
  }
#endif







|
>
>
>
>







89803
89804
89805
89806
89807
89808
89809
89810
89811
89812
89813
89814
89815
89816
89817
89818
89819
89820
89821
  assert( pC!=0 );
  assert( pC->eCurType==CURTYPE_BTREE );
  assert( pC->uc.pCursor!=0 );
  assert( pC->deferredMoveto==0 );
  sqlite3VdbeIncrWriteCounter(p, pC);

#ifdef SQLITE_DEBUG
  if( pOp->p4type==P4_TABLE
   && HasRowid(pOp->p4.pTab)
   && pOp->p5==0
   && sqlite3BtreeCursorIsValidNN(pC->uc.pCursor)
  ){
    /* If p5 is zero, the seek operation that positioned the cursor prior to
    ** OP_Delete will have also set the pC->movetoTarget field to the rowid of
    ** the row that is being deleted */
    i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    assert( CORRUPT_DB || pC->movetoTarget==iKey );
  }
#endif
89386
89387
89388
89389
89390
89391
89392
89393
89394
89395
89396
89397
89398
89399
89400
#endif

  n = sqlite3BtreePayloadSize(pCrsr);
  if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    goto too_big;
  }
  testcase( n==0 );
  rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut);
  if( rc ) goto abort_due_to_error;
  if( !pOp->p3 ) Deephemeralize(pOut);
  UPDATE_MAX_BLOBSIZE(pOut);
  REGISTER_TRACE(pOp->p2, pOut);
  break;
}








|







90022
90023
90024
90025
90026
90027
90028
90029
90030
90031
90032
90033
90034
90035
90036
#endif

  n = sqlite3BtreePayloadSize(pCrsr);
  if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    goto too_big;
  }
  testcase( n==0 );
  rc = sqlite3VdbeMemFromBtreeZeroOffset(pCrsr, n, pOut);
  if( rc ) goto abort_due_to_error;
  if( !pOp->p3 ) Deephemeralize(pOut);
  UPDATE_MAX_BLOBSIZE(pOut);
  REGISTER_TRACE(pOp->p2, pOut);
  break;
}

89764
89765
89766
89767
89768
89769
89770
89771
89772
89773
89774
89775
89776
89777
89778
89779
89780
89781
89782
89783
89784
89785
89786
89787
89788
89789
89790
89791
89792
89793
89794
89795
89796
89797
89798
89799
89800
89801
89802
89803
89804
89805
89806
89807


89808






















89809
89810
89811
89812
89813
89814
89815
** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
** seeks on the cursor or if the most recent seek used a key equivalent
** to P2. 
**
** This instruction only works for indices.  The equivalent instruction
** for tables is OP_Insert.
*/
/* Opcode: SorterInsert P1 P2 * * *
** Synopsis: key=r[P2]
**
** Register P2 holds an SQL index key made using the
** MakeRecord instructions.  This opcode writes that key
** into the sorter P1.  Data for the entry is nil.
*/
case OP_SorterInsert:       /* in2 */
case OP_IdxInsert: {        /* in2 */
  VdbeCursor *pC;
  BtreePayload x;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  sqlite3VdbeIncrWriteCounter(p, pC);
  assert( pC!=0 );
  assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) );
  pIn2 = &aMem[pOp->p2];
  assert( pIn2->flags & MEM_Blob );
  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
  assert( pC->isTable==0 );
  rc = ExpandBlob(pIn2);
  if( rc ) goto abort_due_to_error;
  if( pOp->opcode==OP_SorterInsert ){
    rc = sqlite3VdbeSorterWrite(pC, pIn2);
  }else{
    x.nKey = pIn2->n;
    x.pKey = pIn2->z;
    x.aMem = aMem + pOp->p3;
    x.nMem = (u16)pOp->p4.i;
    rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
         (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), 
        ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
        );
    assert( pC->deferredMoveto==0 );
    pC->cacheStatus = CACHE_STALE;


  }






















  if( rc) goto abort_due_to_error;
  break;
}

/* Opcode: IdxDelete P1 P2 P3 * *
** Synopsis: key=r[P2@P3]
**







<
<
<
<
<
<
<
<








|



|



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







90400
90401
90402
90403
90404
90405
90406








90407
90408
90409
90410
90411
90412
90413
90414
90415
90416
90417
90418
90419
90420
90421
90422



90423
90424
90425
90426
90427
90428
90429
90430
90431
90432
90433
90434
90435
90436
90437
90438
90439
90440
90441
90442
90443
90444
90445
90446
90447
90448
90449
90450
90451
90452
90453
90454
90455
90456
90457
90458
90459
90460
90461
90462
90463
90464
** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
** seeks on the cursor or if the most recent seek used a key equivalent
** to P2. 
**
** This instruction only works for indices.  The equivalent instruction
** for tables is OP_Insert.
*/








case OP_IdxInsert: {        /* in2 */
  VdbeCursor *pC;
  BtreePayload x;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  sqlite3VdbeIncrWriteCounter(p, pC);
  assert( pC!=0 );
  assert( !isSorter(pC) );
  pIn2 = &aMem[pOp->p2];
  assert( pIn2->flags & MEM_Blob );
  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  assert( pC->eCurType==CURTYPE_BTREE );
  assert( pC->isTable==0 );
  rc = ExpandBlob(pIn2);
  if( rc ) goto abort_due_to_error;



  x.nKey = pIn2->n;
  x.pKey = pIn2->z;
  x.aMem = aMem + pOp->p3;
  x.nMem = (u16)pOp->p4.i;
  rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
       (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), 
      ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
      );
  assert( pC->deferredMoveto==0 );
  pC->cacheStatus = CACHE_STALE;
  if( rc) goto abort_due_to_error;
  break;
}

/* Opcode: SorterInsert P1 P2 * * *
** Synopsis: key=r[P2]
**
** Register P2 holds an SQL index key made using the
** MakeRecord instructions.  This opcode writes that key
** into the sorter P1.  Data for the entry is nil.
*/
case OP_SorterInsert: {     /* in2 */
  VdbeCursor *pC;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  sqlite3VdbeIncrWriteCounter(p, pC);
  assert( pC!=0 );
  assert( isSorter(pC) );
  pIn2 = &aMem[pOp->p2];
  assert( pIn2->flags & MEM_Blob );
  assert( pC->isTable==0 );
  rc = ExpandBlob(pIn2);
  if( rc ) goto abort_due_to_error;
  rc = sqlite3VdbeSorterWrite(pC, pIn2);
  if( rc) goto abort_due_to_error;
  break;
}

/* Opcode: IdxDelete P1 P2 P3 * *
** Synopsis: key=r[P2@P3]
**
89926
89927
89928
89929
89930
89931
89932


















89933
89934
89935
89936
89937
89938
89939
    }
  }else{
    assert( pOp->opcode==OP_IdxRowid );
    sqlite3VdbeMemSetNull(&aMem[pOp->p2]);
  }
  break;
}



















/* Opcode: IdxGE P1 P2 P3 P4 P5
** Synopsis: key=r[P3@P4]
**
** The P4 register values beginning with P3 form an unpacked index 
** key that omits the PRIMARY KEY.  Compare this key value against the index 
** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID 







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







90575
90576
90577
90578
90579
90580
90581
90582
90583
90584
90585
90586
90587
90588
90589
90590
90591
90592
90593
90594
90595
90596
90597
90598
90599
90600
90601
90602
90603
90604
90605
90606
    }
  }else{
    assert( pOp->opcode==OP_IdxRowid );
    sqlite3VdbeMemSetNull(&aMem[pOp->p2]);
  }
  break;
}

/* Opcode: FinishSeek P1 * * * *
** 
** If cursor P1 was previously moved via OP_DeferredSeek, complete that
** seek operation now, without further delay.  If the cursor seek has
** already occurred, this instruction is a no-op.
*/
case OP_FinishSeek: {
  VdbeCursor *pC;             /* The P1 index cursor */

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  if( pC->deferredMoveto ){
    rc = sqlite3VdbeFinishMoveto(pC);
    if( rc ) goto abort_due_to_error;
  }
  break;
}

/* Opcode: IdxGE P1 P2 P3 P4 P5
** Synopsis: key=r[P3@P4]
**
** The P4 register values beginning with P3 form an unpacked index 
** key that omits the PRIMARY KEY.  Compare this key value against the index 
** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID 
90622
90623
90624
90625
90626
90627
90628
90629
90630
90631
90632
90633
90634
90635
90636
#ifdef SQLITE_DEBUG
  /* Verify that second and subsequent executions of the same trigger do not
  ** try to reuse register values from the first use. */
  {
    int i;
    for(i=0; i<p->nMem; i++){
      aMem[i].pScopyFrom = 0;  /* Prevent false-positive AboutToChange() errs */
      aMem[i].flags |= MEM_Undefined; /* Cause a fault if this reg is reused */
    }
  }
#endif
  pOp = &aOp[-1];
  goto check_for_interrupt;
}








|







91289
91290
91291
91292
91293
91294
91295
91296
91297
91298
91299
91300
91301
91302
91303
#ifdef SQLITE_DEBUG
  /* Verify that second and subsequent executions of the same trigger do not
  ** try to reuse register values from the first use. */
  {
    int i;
    for(i=0; i<p->nMem; i++){
      aMem[i].pScopyFrom = 0;  /* Prevent false-positive AboutToChange() errs */
      MemSetTypeFlag(&aMem[i], MEM_Undefined); /* Fault if this reg is reused */
    }
  }
#endif
  pOp = &aOp[-1];
  goto check_for_interrupt;
}

91232
91233
91234
91235
91236
91237
91238






























91239
91240
91241
91242
91243
91244
91245
  if( !pOp->p1 ){
    sqlite3ExpirePreparedStatements(db, pOp->p2);
  }else{
    p->expired = pOp->p2+1;
  }
  break;
}































#ifndef SQLITE_OMIT_SHARED_CACHE
/* Opcode: TableLock P1 P2 P3 P4 *
** Synopsis: iDb=P1 root=P2 write=P3
**
** Obtain a lock on a particular table. This instruction is only used when
** the shared-cache feature is enabled. 







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







91899
91900
91901
91902
91903
91904
91905
91906
91907
91908
91909
91910
91911
91912
91913
91914
91915
91916
91917
91918
91919
91920
91921
91922
91923
91924
91925
91926
91927
91928
91929
91930
91931
91932
91933
91934
91935
91936
91937
91938
91939
91940
91941
91942
  if( !pOp->p1 ){
    sqlite3ExpirePreparedStatements(db, pOp->p2);
  }else{
    p->expired = pOp->p2+1;
  }
  break;
}

/* Opcode: CursorLock P1 * * * *
**
** Lock the btree to which cursor P1 is pointing so that the btree cannot be
** written by an other cursor.
*/
case OP_CursorLock: {
  VdbeCursor *pC;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->eCurType==CURTYPE_BTREE );
  sqlite3BtreeCursorPin(pC->uc.pCursor);
  break;
}

/* Opcode: CursorUnlock P1 * * * *
**
** Unlock the btree to which cursor P1 is pointing so that it can be
** written by other cursors.
*/
case OP_CursorUnlock: {
  VdbeCursor *pC;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->eCurType==CURTYPE_BTREE );
  sqlite3BtreeCursorUnpin(pC->uc.pCursor);
  break;
}

#ifndef SQLITE_OMIT_SHARED_CACHE
/* Opcode: TableLock P1 P2 P3 P4 *
** Synopsis: iDb=P1 root=P2 write=P3
**
** Obtain a lock on a particular table. This instruction is only used when
** the shared-cache feature is enabled. 
91477
91478
91479
91480
91481
91482
91483
91484
91485
91486
91487
91488
91489
91490
91491
    break;
  }
  pVtab = pCur->uc.pVCur->pVtab;
  pModule = pVtab->pModule;
  assert( pModule->xColumn );
  memset(&sContext, 0, sizeof(sContext));
  sContext.pOut = pDest;
  testcase( (pOp->p5 & OPFLAG_NOCHNG)==0 && pOp->p5!=0 );
  if( pOp->p5 & OPFLAG_NOCHNG ){
    sqlite3VdbeMemSetNull(pDest);
    pDest->flags = MEM_Null|MEM_Zero;
    pDest->u.nZero = 0;
  }else{
    MemSetTypeFlag(pDest, MEM_Null);
  }







|







92174
92175
92176
92177
92178
92179
92180
92181
92182
92183
92184
92185
92186
92187
92188
    break;
  }
  pVtab = pCur->uc.pVCur->pVtab;
  pModule = pVtab->pModule;
  assert( pModule->xColumn );
  memset(&sContext, 0, sizeof(sContext));
  sContext.pOut = pDest;
  assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
  if( pOp->p5 & OPFLAG_NOCHNG ){
    sqlite3VdbeMemSetNull(pDest);
    pDest->flags = MEM_Null|MEM_Zero;
    pDest->u.nZero = 0;
  }else{
    MemSetTypeFlag(pDest, MEM_Null);
  }
91703
91704
91705
91706
91707
91708
91709
91710
91711
91712
91713
91714
91715
91716
91717
91718
91719
91720
91721
91722
91723
91724
91725
91726
91727
91728
91729
91730
91731
91732
91733
91734
91735
91736
  }
  pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax);
  break;
}
#endif

/* Opcode: Function P1 P2 P3 P4 *
** Synopsis: r[P3]=func(r[P2@P5])
**
** Invoke a user function (P4 is a pointer to an sqlite3_context object that
** contains a pointer to the function to be run) with arguments taken
** from register P2 and successors.  The number of arguments is in
** the sqlite3_context object that P4 points to.
** The result of the function is stored
** in register P3.  Register P3 must not be one of the function inputs.
**
** P1 is a 32-bit bitmask indicating whether or not each argument to the 
** function was determined to be constant at compile time. If the first
** argument was constant then bit 0 of P1 is set. This is used to determine
** whether meta data associated with a user function argument using the
** sqlite3_set_auxdata() API may be safely retained until the next
** invocation of this opcode.
**
** See also: AggStep, AggFinal, PureFunc
*/
/* Opcode: PureFunc P1 P2 P3 P4 *
** Synopsis: r[P3]=func(r[P2@P5])
**
** Invoke a user function (P4 is a pointer to an sqlite3_context object that
** contains a pointer to the function to be run) with arguments taken
** from register P2 and successors.  The number of arguments is in
** the sqlite3_context object that P4 points to.
** The result of the function is stored
** in register P3.  Register P3 must not be one of the function inputs.







|


















|







92400
92401
92402
92403
92404
92405
92406
92407
92408
92409
92410
92411
92412
92413
92414
92415
92416
92417
92418
92419
92420
92421
92422
92423
92424
92425
92426
92427
92428
92429
92430
92431
92432
92433
  }
  pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax);
  break;
}
#endif

/* Opcode: Function P1 P2 P3 P4 *
** Synopsis: r[P3]=func(r[P2@NP])
**
** Invoke a user function (P4 is a pointer to an sqlite3_context object that
** contains a pointer to the function to be run) with arguments taken
** from register P2 and successors.  The number of arguments is in
** the sqlite3_context object that P4 points to.
** The result of the function is stored
** in register P3.  Register P3 must not be one of the function inputs.
**
** P1 is a 32-bit bitmask indicating whether or not each argument to the 
** function was determined to be constant at compile time. If the first
** argument was constant then bit 0 of P1 is set. This is used to determine
** whether meta data associated with a user function argument using the
** sqlite3_set_auxdata() API may be safely retained until the next
** invocation of this opcode.
**
** See also: AggStep, AggFinal, PureFunc
*/
/* Opcode: PureFunc P1 P2 P3 P4 *
** Synopsis: r[P3]=func(r[P2@NP])
**
** Invoke a user function (P4 is a pointer to an sqlite3_context object that
** contains a pointer to the function to be run) with arguments taken
** from register P2 and successors.  The number of arguments is in
** the sqlite3_context object that P4 points to.
** The result of the function is stored
** in register P3.  Register P3 must not be one of the function inputs.
91937
91938
91939
91940
91941
91942
91943

















































91944
91945
91946
91947
91948
91949
91950
** an active statement journal.
*/
case OP_Abortable: {
  sqlite3VdbeAssertAbortable(p);
  break;
}
#endif


















































/* Opcode: Noop * * * * *
**
** Do nothing.  This instruction is often useful as a jump
** destination.
*/
/*







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







92634
92635
92636
92637
92638
92639
92640
92641
92642
92643
92644
92645
92646
92647
92648
92649
92650
92651
92652
92653
92654
92655
92656
92657
92658
92659
92660
92661
92662
92663
92664
92665
92666
92667
92668
92669
92670
92671
92672
92673
92674
92675
92676
92677
92678
92679
92680
92681
92682
92683
92684
92685
92686
92687
92688
92689
92690
92691
92692
92693
92694
92695
92696
** an active statement journal.
*/
case OP_Abortable: {
  sqlite3VdbeAssertAbortable(p);
  break;
}
#endif

#ifdef SQLITE_DEBUG
/* Opcode:  ReleaseReg   P1 P2 P3 * P5
** Synopsis: release r[P1@P2] mask P3
**
** Release registers from service.  Any content that was in the
** the registers is unreliable after this opcode completes.
**
** The registers released will be the P2 registers starting at P1,
** except if bit ii of P3 set, then do not release register P1+ii.
** In other words, P3 is a mask of registers to preserve.
**
** Releasing a register clears the Mem.pScopyFrom pointer.  That means
** that if the content of the released register was set using OP_SCopy,
** a change to the value of the source register for the OP_SCopy will no longer
** generate an assertion fault in sqlite3VdbeMemAboutToChange().
**
** If P5 is set, then all released registers have their type set
** to MEM_Undefined so that any subsequent attempt to read the released
** register (before it is reinitialized) will generate an assertion fault.
**
** P5 ought to be set on every call to this opcode.
** However, there are places in the code generator will release registers
** before their are used, under the (valid) assumption that the registers
** will not be reallocated for some other purpose before they are used and
** hence are safe to release.
**
** This opcode is only available in testing and debugging builds.  It is
** not generated for release builds.  The purpose of this opcode is to help
** validate the generated bytecode.  This opcode does not actually contribute
** to computing an answer.
*/
case OP_ReleaseReg: {
  Mem *pMem;
  int i;
  u32 constMask;
  assert( pOp->p1>0 );
  assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
  pMem = &aMem[pOp->p1];
  constMask = pOp->p3;
  for(i=0; i<pOp->p2; i++, pMem++){
    if( i>=32 || (constMask & MASKBIT32(i))==0 ){
      pMem->pScopyFrom = 0;
      if( i<32 && pOp->p5 ) MemSetTypeFlag(pMem, MEM_Undefined);
    }
  }
  break;
}
#endif

/* Opcode: Noop * * * * *
**
** Do nothing.  This instruction is often useful as a jump
** destination.
*/
/*
91989
91990
91991
91992
91993
91994
91995






91996
91997
91998
91999
92000
92001
92002
      if( rc!=0 ) printf("rc=%d\n",rc);
      if( opProperty & (OPFLG_OUT2) ){
        registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]);
      }
      if( opProperty & OPFLG_OUT3 ){
        registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
      }






    }
#endif  /* SQLITE_DEBUG */
#endif  /* NDEBUG */
  }  /* The end of the for(;;) loop the loops through opcodes */

  /* If we reach this point, it means that execution is finished with
  ** an error of some kind.







>
>
>
>
>
>







92735
92736
92737
92738
92739
92740
92741
92742
92743
92744
92745
92746
92747
92748
92749
92750
92751
92752
92753
92754
      if( rc!=0 ) printf("rc=%d\n",rc);
      if( opProperty & (OPFLG_OUT2) ){
        registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]);
      }
      if( opProperty & OPFLG_OUT3 ){
        registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
      }
      if( opProperty==0xff ){
        /* Never happens.  This code exists to avoid a harmless linkage
        ** warning aboud sqlite3VdbeRegisterDump() being defined but not
        ** used. */
        sqlite3VdbeRegisterDump(p);
      }
    }
#endif  /* SQLITE_DEBUG */
#endif  /* NDEBUG */
  }  /* The end of the for(;;) loop the loops through opcodes */

  /* If we reach this point, it means that execution is finished with
  ** an error of some kind.
92056
92057
92058
92059
92060
92061
92062
92063
92064
92065
92066
92067
92068
92069
92070
  rc = SQLITE_NOMEM_BKPT;
  goto abort_due_to_error;

  /* Jump to here if the sqlite3_interrupt() API sets the interrupt
  ** flag.
  */
abort_due_to_interrupt:
  assert( db->u1.isInterrupted );
  rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
  p->rc = rc;
  sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
  goto abort_due_to_error;
}









|







92808
92809
92810
92811
92812
92813
92814
92815
92816
92817
92818
92819
92820
92821
92822
  rc = SQLITE_NOMEM_BKPT;
  goto abort_due_to_error;

  /* Jump to here if the sqlite3_interrupt() API sets the interrupt
  ** flag.
  */
abort_due_to_interrupt:
  assert( AtomicLoad(&db->u1.isInterrupted) );
  rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
  p->rc = rc;
  sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
  goto abort_due_to_error;
}


93394
93395
93396
93397
93398
93399
93400
93401
93402
93403
93404
93405
93406
93407
93408
93409
  const u8 * const v1 = &p1[ p1[0] ];   /* Pointer to value 1 */
  const u8 * const v2 = &p2[ p2[0] ];   /* Pointer to value 2 */

  int n1;
  int n2;
  int res;

  getVarint32(&p1[1], n1);
  getVarint32(&p2[1], n2);
  res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2);
  if( res==0 ){
    res = n1 - n2;
  }

  if( res==0 ){
    if( pTask->pSorter->pKeyInfo->nKeyField>1 ){







|
|







94146
94147
94148
94149
94150
94151
94152
94153
94154
94155
94156
94157
94158
94159
94160
94161
  const u8 * const v1 = &p1[ p1[0] ];   /* Pointer to value 1 */
  const u8 * const v2 = &p2[ p2[0] ];   /* Pointer to value 2 */

  int n1;
  int n2;
  int res;

  getVarint32NR(&p1[1], n1);
  getVarint32NR(&p2[1], n2);
  res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2);
  if( res==0 ){
    res = n1 - n2;
  }

  if( res==0 ){
    if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
94352
94353
94354
94355
94356
94357
94358
94359
94360
94361
94362
94363
94364
94365
94366
  int bFlush;                     /* True to flush contents of memory to PMA */
  int nReq;                       /* Bytes of memory required */
  int nPMA;                       /* Bytes of PMA space required */
  int t;                          /* serial type of first record field */

  assert( pCsr->eCurType==CURTYPE_SORTER );
  pSorter = pCsr->uc.pSorter;
  getVarint32((const u8*)&pVal->z[1], t);
  if( t>0 && t<10 && t!=7 ){
    pSorter->typeMask &= SORTER_TYPE_INTEGER;
  }else if( t>10 && (t & 0x01) ){
    pSorter->typeMask &= SORTER_TYPE_TEXT;
  }else{
    pSorter->typeMask = 0;
  }







|







95104
95105
95106
95107
95108
95109
95110
95111
95112
95113
95114
95115
95116
95117
95118
  int bFlush;                     /* True to flush contents of memory to PMA */
  int nReq;                       /* Bytes of memory required */
  int nPMA;                       /* Bytes of PMA space required */
  int t;                          /* serial type of first record field */

  assert( pCsr->eCurType==CURTYPE_SORTER );
  pSorter = pCsr->uc.pSorter;
  getVarint32NR((const u8*)&pVal->z[1], t);
  if( t>0 && t<10 && t!=7 ){
    pSorter->typeMask &= SORTER_TYPE_INTEGER;
  }else if( t>10 && (t & 0x01) ){
    pSorter->typeMask &= SORTER_TYPE_TEXT;
  }else{
    pSorter->typeMask = 0;
  }
95847
95848
95849
95850
95851
95852
95853
95854
95855

95856
95857
95858
95859
95860
95861
95862
  int rc;
  testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
  testcase( ExprHasProperty(pExpr, EP_Reduced) );
  while(1){
    rc = pWalker->xExprCallback(pWalker, pExpr);
    if( rc ) return rc & WRC_Abort;
    if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
      if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
       assert( pExpr->x.pList==0 || pExpr->pRight==0 );

      if( pExpr->pRight ){
        assert( !ExprHasProperty(pExpr, EP_WinFunc) );
        pExpr = pExpr->pRight;
        continue;
      }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
        assert( !ExprHasProperty(pExpr, EP_WinFunc) );
        if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;







<
|
>







96599
96600
96601
96602
96603
96604
96605

96606
96607
96608
96609
96610
96611
96612
96613
96614
  int rc;
  testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
  testcase( ExprHasProperty(pExpr, EP_Reduced) );
  while(1){
    rc = pWalker->xExprCallback(pWalker, pExpr);
    if( rc ) return rc & WRC_Abort;
    if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){

      assert( pExpr->x.pList==0 || pExpr->pRight==0 );
      if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
      if( pExpr->pRight ){
        assert( !ExprHasProperty(pExpr, EP_WinFunc) );
        pExpr = pExpr->pRight;
        continue;
      }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
        assert( !ExprHasProperty(pExpr, EP_WinFunc) );
        if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
95930
95931
95932
95933
95934
95935
95936
95937
95938
95939
95940
95941
95942
95943
95944
95945

95946
95947
95948
95949
95950
95951
95952
*/
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
  SrcList *pSrc;
  int i;
  struct SrcList_item *pItem;

  pSrc = p->pSrc;
  assert( pSrc!=0 );
  for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
    if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
      return WRC_Abort;
    }
    if( pItem->fg.isTabFunc
     && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
    ){
      return WRC_Abort;

    }
  }
  return WRC_Continue;
} 

/*
** Call sqlite3WalkExpr() for every expression in Select statement p.







|
|
|
|
|
|
|
|
|
>







96682
96683
96684
96685
96686
96687
96688
96689
96690
96691
96692
96693
96694
96695
96696
96697
96698
96699
96700
96701
96702
96703
96704
96705
*/
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
  SrcList *pSrc;
  int i;
  struct SrcList_item *pItem;

  pSrc = p->pSrc;
  if( pSrc ){
    for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
      if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
        return WRC_Abort;
      }
      if( pItem->fg.isTabFunc
       && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
      ){
        return WRC_Abort;
      }
    }
  }
  return WRC_Continue;
} 

/*
** Call sqlite3WalkExpr() for every expression in Select statement p.
96117
96118
96119
96120
96121
96122
96123
96124
96125
96126
96127
96128
96129
96130



96131
96132
96133
96134
96135
96136
96137
/*
** Subqueries stores the original database, table and column names for their
** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
** Check to see if the zSpan given to this routine matches the zDb, zTab,
** and zCol.  If any of zDb, zTab, and zCol are NULL then those fields will
** match anything.
*/
SQLITE_PRIVATE int sqlite3MatchSpanName(
  const char *zSpan,
  const char *zCol,
  const char *zTab,
  const char *zDb
){
  int n;



  for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
  if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
    return 0;
  }
  zSpan += n+1;
  for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
  if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){







|
|





>
>
>







96870
96871
96872
96873
96874
96875
96876
96877
96878
96879
96880
96881
96882
96883
96884
96885
96886
96887
96888
96889
96890
96891
96892
96893
/*
** Subqueries stores the original database, table and column names for their
** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
** Check to see if the zSpan given to this routine matches the zDb, zTab,
** and zCol.  If any of zDb, zTab, and zCol are NULL then those fields will
** match anything.
*/
SQLITE_PRIVATE int sqlite3MatchEName(
  const struct ExprList_item *pItem,
  const char *zCol,
  const char *zTab,
  const char *zDb
){
  int n;
  const char *zSpan;
  if( pItem->eEName!=ENAME_TAB ) return 0;
  zSpan = pItem->zEName;
  for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
  if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
    return 0;
  }
  zSpan += n+1;
  for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
  if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){
96156
96157
96158
96159
96160
96161
96162

























96163
96164
96165
96166
96167
96168
96169
    }
    return (db->flags & SQLITE_DqsDDL)!=0;
  }else{
    /* Currently parsing a DML statement */
    return (db->flags & SQLITE_DqsDML)!=0;
  }
}


























/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
** that name in the set of source tables in pSrcList and make the pExpr 
** expression node refer back to that source column.  The following changes
** are made to pExpr:
**







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







96912
96913
96914
96915
96916
96917
96918
96919
96920
96921
96922
96923
96924
96925
96926
96927
96928
96929
96930
96931
96932
96933
96934
96935
96936
96937
96938
96939
96940
96941
96942
96943
96944
96945
96946
96947
96948
96949
96950
    }
    return (db->flags & SQLITE_DqsDDL)!=0;
  }else{
    /* Currently parsing a DML statement */
    return (db->flags & SQLITE_DqsDML)!=0;
  }
}

/*
** The argument is guaranteed to be a non-NULL Expr node of type TK_COLUMN.
** return the appropriate colUsed mask.
*/
SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr *pExpr){
  int n;
  Table *pExTab;

  n = pExpr->iColumn;
  pExTab = pExpr->y.pTab;
  assert( pExTab!=0 );
  if( (pExTab->tabFlags & TF_HasGenerated)!=0
   && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0 
  ){
    testcase( pExTab->nCol==BMS-1 );
    testcase( pExTab->nCol==BMS );
    return pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1;
  }else{
    testcase( n==BMS-1 );
    testcase( n==BMS );
    if( n>=BMS ) n = BMS-1;
    return ((Bitmask)1)<<n;
  }
}

/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
** that name in the set of source tables in pSrcList and make the pExpr 
** expression node refer back to that source column.  The following changes
** are made to pExpr:
**
96234
96235
96236
96237
96238
96239
96240






96241
96242
96243
96244
96245
96246
96247
96248
96249
96250
96251

96252
96253
96254
96255
96256
96257
96258
96259
96260
96261
96262
96263
96264
96265
96266
      for(i=0; i<db->nDb; i++){
        assert( db->aDb[i].zDbSName );
        if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){
          pSchema = db->aDb[i].pSchema;
          break;
        }
      }






    }
  }

  /* Start at the inner-most context and move outward until a match is found */
  assert( pNC && cnt==0 );
  do{
    ExprList *pEList;
    SrcList *pSrcList = pNC->pSrcList;

    if( pSrcList ){
      for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){

        pTab = pItem->pTab;
        assert( pTab!=0 && pTab->zName!=0 );
        assert( pTab->nCol>0 );
        if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
          int hit = 0;
          pEList = pItem->pSelect->pEList;
          for(j=0; j<pEList->nExpr; j++){
            if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
              cnt++;
              cntTab = 2;
              pMatch = pItem;
              pExpr->iColumn = j;
              hit = 1;
            }
          }







>
>
>
>
>
>











>







|







97015
97016
97017
97018
97019
97020
97021
97022
97023
97024
97025
97026
97027
97028
97029
97030
97031
97032
97033
97034
97035
97036
97037
97038
97039
97040
97041
97042
97043
97044
97045
97046
97047
97048
97049
97050
97051
97052
97053
97054
      for(i=0; i<db->nDb; i++){
        assert( db->aDb[i].zDbSName );
        if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){
          pSchema = db->aDb[i].pSchema;
          break;
        }
      }
      if( i==db->nDb && sqlite3StrICmp("main", zDb)==0 ){
        /* This branch is taken when the main database has been renamed
        ** using SQLITE_DBCONFIG_MAINDBNAME. */
        pSchema = db->aDb[0].pSchema;
        zDb = db->aDb[0].zDbSName;
      }
    }
  }

  /* Start at the inner-most context and move outward until a match is found */
  assert( pNC && cnt==0 );
  do{
    ExprList *pEList;
    SrcList *pSrcList = pNC->pSrcList;

    if( pSrcList ){
      for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
        u8 hCol;
        pTab = pItem->pTab;
        assert( pTab!=0 && pTab->zName!=0 );
        assert( pTab->nCol>0 );
        if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
          int hit = 0;
          pEList = pItem->pSelect->pEList;
          for(j=0; j<pEList->nExpr; j++){
            if( sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
              cnt++;
              cntTab = 2;
              pMatch = pItem;
              pExpr->iColumn = j;
              hit = 1;
            }
          }
96278
96279
96280
96281
96282
96283
96284

96285
96286
96287
96288
96289
96290
96291
96292
96293
          if( IN_RENAME_OBJECT && pItem->zAlias ){
            sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
          }
        }
        if( 0==(cntTab++) ){
          pMatch = pItem;
        }

        for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
          if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
            /* If there has been exactly one prior match and this match
            ** is for the right-hand table of a NATURAL JOIN or is in a 
            ** USING clause, then skip this match.
            */
            if( cnt==1 ){
              if( pItem->fg.jointype & JT_NATURAL ) continue;
              if( nameInUsingClause(pItem->pUsing, zCol) ) continue;







>

|







97066
97067
97068
97069
97070
97071
97072
97073
97074
97075
97076
97077
97078
97079
97080
97081
97082
          if( IN_RENAME_OBJECT && pItem->zAlias ){
            sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
          }
        }
        if( 0==(cntTab++) ){
          pMatch = pItem;
        }
        hCol = sqlite3StrIHash(zCol);
        for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
          if( pCol->hName==hCol && sqlite3StrICmp(pCol->zName, zCol)==0 ){
            /* If there has been exactly one prior match and this match
            ** is for the right-hand table of a NATURAL JOIN or is in a 
            ** USING clause, then skip this match.
            */
            if( cnt==1 ){
              if( pItem->fg.jointype & JT_NATURAL ) continue;
              if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
96340
96341
96342
96343
96344
96345
96346

96347
96348
96349
96350
96351
96352
96353
96354
96355
96356
96357
          pExpr->iTable = 2;
        }
      }
#endif /* SQLITE_OMIT_UPSERT */

      if( pTab ){ 
        int iCol;

        pSchema = pTab->pSchema;
        cntTab++;
        for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){
          if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
            if( iCol==pTab->iPKey ){
              iCol = -1;
            }
            break;
          }
        }
        if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){







>



|







97129
97130
97131
97132
97133
97134
97135
97136
97137
97138
97139
97140
97141
97142
97143
97144
97145
97146
97147
          pExpr->iTable = 2;
        }
      }
#endif /* SQLITE_OMIT_UPSERT */

      if( pTab ){ 
        int iCol;
        u8 hCol = sqlite3StrIHash(zCol);
        pSchema = pTab->pSchema;
        cntTab++;
        for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){
          if( pCol->hName==hCol && sqlite3StrICmp(pCol->zName, zCol)==0 ){
            if( iCol==pTab->iPKey ){
              iCol = -1;
            }
            break;
          }
        }
        if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
96433
96434
96435
96436
96437
96438
96439
96440

96441

96442
96443
96444
96445
96446
96447
96448
96449
96450
96451


96452
96453
96454
96455
96456
96457
96458
    if( (pNC->ncFlags & NC_UEList)!=0
     && cnt==0
     && zTab==0
    ){
      pEList = pNC->uNC.pEList;
      assert( pEList!=0 );
      for(j=0; j<pEList->nExpr; j++){
        char *zAs = pEList->a[j].zName;

        if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){

          Expr *pOrig;
          assert( pExpr->pLeft==0 && pExpr->pRight==0 );
          assert( pExpr->x.pList==0 );
          assert( pExpr->x.pSelect==0 );
          pOrig = pEList->a[j].pExpr;
          if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){
            sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
            return WRC_Abort;
          }
          if( (pNC->ncFlags&NC_AllowWin)==0 && ExprHasProperty(pOrig, EP_Win) ){


            sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs);
            return WRC_Abort;
          }
          if( sqlite3ExprVectorSize(pOrig)!=1 ){
            sqlite3ErrorMsg(pParse, "row value misused");
            return WRC_Abort;
          }







|
>
|
>









|
>
>







97223
97224
97225
97226
97227
97228
97229
97230
97231
97232
97233
97234
97235
97236
97237
97238
97239
97240
97241
97242
97243
97244
97245
97246
97247
97248
97249
97250
97251
97252
    if( (pNC->ncFlags & NC_UEList)!=0
     && cnt==0
     && zTab==0
    ){
      pEList = pNC->uNC.pEList;
      assert( pEList!=0 );
      for(j=0; j<pEList->nExpr; j++){
        char *zAs = pEList->a[j].zEName;
        if( pEList->a[j].eEName==ENAME_NAME
         && sqlite3_stricmp(zAs, zCol)==0
        ){
          Expr *pOrig;
          assert( pExpr->pLeft==0 && pExpr->pRight==0 );
          assert( pExpr->x.pList==0 );
          assert( pExpr->x.pSelect==0 );
          pOrig = pEList->a[j].pExpr;
          if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){
            sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
            return WRC_Abort;
          }
          if( ExprHasProperty(pOrig, EP_Win)
           && ((pNC->ncFlags&NC_AllowWin)==0 || pNC!=pTopNC )
          ){
            sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs);
            return WRC_Abort;
          }
          if( sqlite3ExprVectorSize(pOrig)!=1 ){
            sqlite3ErrorMsg(pParse, "row value misused");
            return WRC_Abort;
          }
96536
96537
96538
96539
96540
96541
96542
96543





96544



96545
96546
96547
96548
96549
96550
96551
96552
96553
96554
96555
96556
96557
96558
96559
96560
96561
    }
    pParse->checkSchema = 1;
    pTopNC->nErr++;
  }

  /* If a column from a table in pSrcList is referenced, then record
  ** this fact in the pSrcList.a[].colUsed bitmask.  Column 0 causes
  ** bit 0 to be set.  Column 1 sets bit 1.  And so forth.  If the





  ** column number is greater than the number of bits in the bitmask



  ** then set the high-order bit of the bitmask.
  */
  if( pExpr->iColumn>=0 && pMatch!=0 ){
    int n = pExpr->iColumn;
    testcase( n==BMS-1 );
    if( n>=BMS ){
      n = BMS-1;
    }
    assert( pMatch->iCursor==pExpr->iTable );
    pMatch->colUsed |= ((Bitmask)1)<<n;
  }

  /* Clean up and return
  */
  sqlite3ExprDelete(db, pExpr->pLeft);
  pExpr->pLeft = 0;
  sqlite3ExprDelete(db, pExpr->pRight);







|
>
>
>
>
>
|
>
>
>
|


<
<
<
<
<
<
|







97330
97331
97332
97333
97334
97335
97336
97337
97338
97339
97340
97341
97342
97343
97344
97345
97346
97347
97348
97349






97350
97351
97352
97353
97354
97355
97356
97357
    }
    pParse->checkSchema = 1;
    pTopNC->nErr++;
  }

  /* If a column from a table in pSrcList is referenced, then record
  ** this fact in the pSrcList.a[].colUsed bitmask.  Column 0 causes
  ** bit 0 to be set.  Column 1 sets bit 1.  And so forth.  Bit 63 is
  ** set if the 63rd or any subsequent column is used.
  **
  ** The colUsed mask is an optimization used to help determine if an
  ** index is a covering index.  The correct answer is still obtained
  ** if the mask contains extra set bits.  However, it is important to
  ** avoid setting bits beyond the maximum column number of the table.
  ** (See ticket [b92e5e8ec2cdbaa1]).
  **
  ** If a generated column is referenced, set bits for every column
  ** of the table.
  */
  if( pExpr->iColumn>=0 && pMatch!=0 ){






    pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
  }

  /* Clean up and return
  */
  sqlite3ExprDelete(db, pExpr->pLeft);
  pExpr->pLeft = 0;
  sqlite3ExprDelete(db, pExpr->pRight);
96586
96587
96588
96589
96590
96591
96592
96593
96594
96595
96596
96597
96598







96599
96600
96601

96602
96603
96604
96605
96606
96607
96608
96609












96610
96611
96612
96613
96614
96615

96616
96617
96618
96619
96620
96621
96622
96623
96624
96625
96626
96627

96628
96629



96630
96631
96632
96633
96634
96635
96636
** Allocate and return a pointer to an expression to load the column iCol
** from datasource iSrc in SrcList pSrc.
*/
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
  Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
  if( p ){
    struct SrcList_item *pItem = &pSrc->a[iSrc];
    p->y.pTab = pItem->pTab;
    p->iTable = pItem->iCursor;
    if( p->y.pTab->iPKey==iCol ){
      p->iColumn = -1;
    }else{
      p->iColumn = (ynVar)iCol;







      testcase( iCol==BMS );
      testcase( iCol==BMS-1 );
      pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);

    }
  }
  return p;
}

/*
** Report an error that an expression is not valid for some set of
** pNC->ncFlags values determined by validMask.












*/
static void notValid(
  Parse *pParse,       /* Leave error message here */
  NameContext *pNC,    /* The name context */
  const char *zMsg,    /* Type of error */
  int validMask        /* Set of contexts for which prohibited */

){
  assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 );
  if( (pNC->ncFlags & validMask)!=0 ){
    const char *zIn = "partial index WHERE clauses";
    if( pNC->ncFlags & NC_IdxExpr )      zIn = "index expressions";
#ifndef SQLITE_OMIT_CHECK
    else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
#endif
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
    else if( pNC->ncFlags & NC_GenCol ) zIn = "generated columns";
#endif
    sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);

  }
}




/*
** Expression p should encode a floating point value between 1.0 and 0.0.
** Return 1024 times this value.  Or return -1 if p is not a floating point
** value between 1.0 and 0.0.
*/
static int exprProbability(Expr *p){







|





>
>
>
>
>
>
>
|
|
|
>








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

|
|
|
|
<
>

<
<
|
|

|


|

|
>
|
<
>
>
>







97382
97383
97384
97385
97386
97387
97388
97389
97390
97391
97392
97393
97394
97395
97396
97397
97398
97399
97400
97401
97402
97403
97404
97405
97406
97407
97408
97409
97410
97411
97412
97413
97414
97415
97416
97417
97418
97419
97420
97421
97422
97423
97424
97425
97426
97427
97428
97429
97430

97431
97432


97433
97434
97435
97436
97437
97438
97439
97440
97441
97442
97443

97444
97445
97446
97447
97448
97449
97450
97451
97452
97453
** Allocate and return a pointer to an expression to load the column iCol
** from datasource iSrc in SrcList pSrc.
*/
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
  Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
  if( p ){
    struct SrcList_item *pItem = &pSrc->a[iSrc];
    Table *pTab = p->y.pTab = pItem->pTab;
    p->iTable = pItem->iCursor;
    if( p->y.pTab->iPKey==iCol ){
      p->iColumn = -1;
    }else{
      p->iColumn = (ynVar)iCol;
      if( (pTab->tabFlags & TF_HasGenerated)!=0
       && (pTab->aCol[iCol].colFlags & COLFLAG_GENERATED)!=0
      ){
        testcase( pTab->nCol==63 );
        testcase( pTab->nCol==64 );
        pItem->colUsed = pTab->nCol>=64 ? ALLBITS : MASKBIT(pTab->nCol)-1;
      }else{
        testcase( iCol==BMS );
        testcase( iCol==BMS-1 );
        pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
      }
    }
  }
  return p;
}

/*
** Report an error that an expression is not valid for some set of
** pNC->ncFlags values determined by validMask.
**
** static void notValid(
**   Parse *pParse,       // Leave error message here
**   NameContext *pNC,    // The name context 
**   const char *zMsg,    // Type of error
**   int validMask,       // Set of contexts for which prohibited
**   Expr *pExpr          // Invalidate this expression on error
** ){...}
**
** As an optimization, since the conditional is almost always false
** (because errors are rare), the conditional is moved outside of the
** function call using a macro.
*/
static void notValidImpl(
   Parse *pParse,       /* Leave error message here */
   NameContext *pNC,    /* The name context */
   const char *zMsg,    /* Type of error */

   Expr *pExpr          /* Invalidate this expression on error */
){


  const char *zIn = "partial index WHERE clauses";
  if( pNC->ncFlags & NC_IdxExpr )      zIn = "index expressions";
#ifndef SQLITE_OMIT_CHECK
  else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
#endif
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
  else if( pNC->ncFlags & NC_GenCol ) zIn = "generated columns";
#endif
  sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
  if( pExpr ) pExpr->op = TK_NULL;
}

#define sqlite3ResolveNotValid(P,N,M,X,E) \
  assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \
  if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E);

/*
** Expression p should encode a floating point value between 1.0 and 0.0.
** Return 1024 times this value.  Or return -1 if p is not a floating point
** value between 1.0 and 0.0.
*/
static int exprProbability(Expr *p){
96711
96712
96713
96714
96715
96716
96717


96718

96719
96720
96721
96722
96723
96724
96725

      if( pExpr->op==TK_ID ){
        zDb = 0;
        zTable = 0;
        zColumn = pExpr->u.zToken;
      }else{
        Expr *pLeft = pExpr->pLeft;


        notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr|NC_GenCol);

        pRight = pExpr->pRight;
        if( pRight->op==TK_ID ){
          zDb = 0;
        }else{
          assert( pRight->op==TK_DOT );
          zDb = pLeft->u.zToken;
          pLeft = pRight->pLeft;







>
>
|
>







97528
97529
97530
97531
97532
97533
97534
97535
97536
97537
97538
97539
97540
97541
97542
97543
97544
97545

      if( pExpr->op==TK_ID ){
        zDb = 0;
        zTable = 0;
        zColumn = pExpr->u.zToken;
      }else{
        Expr *pLeft = pExpr->pLeft;
        testcase( pNC->ncFlags & NC_IdxExpr );
        testcase( pNC->ncFlags & NC_GenCol );
        sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator",
                               NC_IdxExpr|NC_GenCol, 0);
        pRight = pExpr->pRight;
        if( pRight->op==TK_ID ){
          zDb = 0;
        }else{
          assert( pRight->op==TK_DOT );
          zDb = pLeft->u.zToken;
          pLeft = pRight->pLeft;
96805
96806
96807
96808
96809
96810
96811

96812
96813
96814


96815

96816
96817
96818

96819
96820
96821
96822
96823
96824
96825


96826
96827
96828
96829
96830
96831
96832
96833
96834
96835
96836
96837
96838
96839
96840
96841
96842
96843
          /* For the purposes of the EP_ConstFunc flag, date and time
          ** functions and other functions that change slowly are considered
          ** constant because they are constant for the duration of one query.
          ** This allows them to be factored out of inner loops. */
          ExprSetProperty(pExpr,EP_ConstFunc);
        }
        if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){

          /* Date/time functions that use 'now', and other functions like
          ** sqlite_version() that might change over time cannot be used
          ** in an index. */


          notValid(pParse, pNC, "non-deterministic functions", NC_SelfRef);

        }else{
          assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */
          pExpr->op2 = pNC->ncFlags & NC_SelfRef;

        }
        if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0
         && pParse->nested==0
         && sqlite3Config.bInternalFunctions==0
        ){
          /* Internal-use-only functions are disallowed unless the
          ** SQL is being compiled using sqlite3NestedParse() */


          no_such_func = 1;
          pDef = 0;
        }else
        if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
         && ExprHasProperty(pExpr, EP_Indirect)
         && !IN_RENAME_OBJECT
        ){
          /* Functions tagged with SQLITE_DIRECTONLY may not be used
          ** inside of triggers and views */
          sqlite3ErrorMsg(pParse, "%s() prohibited in triggers and views",
                          pDef->zName);
        }
      }

      if( 0==IN_RENAME_OBJECT ){
#ifndef SQLITE_OMIT_WINDOWFUNC
        assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
          || (pDef->xValue==0 && pDef->xInverse==0)







>
|

|
>
>
|
>



>



|


|
>
>



|
<


<
<
|
<







97625
97626
97627
97628
97629
97630
97631
97632
97633
97634
97635
97636
97637
97638
97639
97640
97641
97642
97643
97644
97645
97646
97647
97648
97649
97650
97651
97652
97653
97654
97655
97656

97657
97658


97659

97660
97661
97662
97663
97664
97665
97666
          /* For the purposes of the EP_ConstFunc flag, date and time
          ** functions and other functions that change slowly are considered
          ** constant because they are constant for the duration of one query.
          ** This allows them to be factored out of inner loops. */
          ExprSetProperty(pExpr,EP_ConstFunc);
        }
        if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){
          /* Clearly non-deterministic functions like random(), but also
          ** date/time functions that use 'now', and other functions like
          ** sqlite_version() that might change over time cannot be used
          ** in an index or generated column.  Curiously, they can be used
          ** in a CHECK constraint.  SQLServer, MySQL, and PostgreSQL all
          ** all this. */
          sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions",
                                 NC_IdxExpr|NC_PartIdx|NC_GenCol, 0);
        }else{
          assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */
          pExpr->op2 = pNC->ncFlags & NC_SelfRef;
          if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL);
        }
        if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0
         && pParse->nested==0
         && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0
        ){
          /* Internal-use-only functions are disallowed unless the
          ** SQL is being compiled using sqlite3NestedParse() or
          ** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be
          ** used to activate internal functionsn for testing purposes */
          no_such_func = 1;
          pDef = 0;
        }else
        if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0

         && !IN_RENAME_OBJECT
        ){


          sqlite3ExprFunctionUsable(pParse, pExpr, pDef);

        }
      }

      if( 0==IN_RENAME_OBJECT ){
#ifndef SQLITE_OMIT_WINDOWFUNC
        assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
          || (pDef->xValue==0 && pDef->xInverse==0)
96910
96911
96912
96913
96914
96915
96916
96917
96918
96919
96920
96921
96922
96923
96924
      sqlite3WalkExprList(pWalker, pList);
      if( is_agg ){
#ifndef SQLITE_OMIT_WINDOWFUNC
        if( pWin ){
          Select *pSel = pNC->pWinSelect;
          assert( pWin==pExpr->y.pWin );
          if( IN_RENAME_OBJECT==0 ){
            sqlite3WindowUpdate(pParse, pSel->pWinDefn, pWin, pDef);
          }
          sqlite3WalkExprList(pWalker, pWin->pPartition);
          sqlite3WalkExprList(pWalker, pWin->pOrderBy);
          sqlite3WalkExpr(pWalker, pWin->pFilter);
          sqlite3WindowLink(pSel, pWin);
          pNC->ncFlags |= NC_HasWin;
        }else







|







97733
97734
97735
97736
97737
97738
97739
97740
97741
97742
97743
97744
97745
97746
97747
      sqlite3WalkExprList(pWalker, pList);
      if( is_agg ){
#ifndef SQLITE_OMIT_WINDOWFUNC
        if( pWin ){
          Select *pSel = pNC->pWinSelect;
          assert( pWin==pExpr->y.pWin );
          if( IN_RENAME_OBJECT==0 ){
            sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
          }
          sqlite3WalkExprList(pWalker, pWin->pPartition);
          sqlite3WalkExprList(pWalker, pWin->pOrderBy);
          sqlite3WalkExpr(pWalker, pWin->pFilter);
          sqlite3WindowLink(pSel, pWin);
          pNC->ncFlags |= NC_HasWin;
        }else
96955
96956
96957
96958
96959
96960
96961




96962
96963
96964
96965
96966
96967
96968
96969
96970
96971
96972
96973




96974
96975
96976
96977
96978
96979
96980
96981
96982
96983
96984
96985
96986
96987
96988
96989
96990
96991
    case TK_SELECT:
    case TK_EXISTS:  testcase( pExpr->op==TK_EXISTS );
#endif
    case TK_IN: {
      testcase( pExpr->op==TK_IN );
      if( ExprHasProperty(pExpr, EP_xIsSelect) ){
        int nRef = pNC->nRef;




        notValid(pParse, pNC, "subqueries", 
                 NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol);
        sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
        assert( pNC->nRef>=nRef );
        if( nRef!=pNC->nRef ){
          ExprSetProperty(pExpr, EP_VarSelect);
          pNC->ncFlags |= NC_VarSelect;
        }
      }
      break;
    }
    case TK_VARIABLE: {




      notValid(pParse, pNC, "parameters",
               NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol);
      break;
    }
    case TK_IS:
    case TK_ISNOT: {
      Expr *pRight = sqlite3ExprSkipCollateAndLikely(pExpr->pRight);
      assert( !ExprHasProperty(pExpr, EP_Reduced) );
      /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
      ** and "x IS NOT FALSE". */
      if( pRight->op==TK_ID ){
        int rc = resolveExprStep(pWalker, pRight);
        if( rc==WRC_Abort ) return WRC_Abort;
        if( pRight->op==TK_TRUEFALSE ){
          pExpr->op2 = pExpr->op;
          pExpr->op = TK_TRUTH;
          return WRC_Continue;
        }







>
>
>
>
|
|










>
>
>
>
|
|








|







97778
97779
97780
97781
97782
97783
97784
97785
97786
97787
97788
97789
97790
97791
97792
97793
97794
97795
97796
97797
97798
97799
97800
97801
97802
97803
97804
97805
97806
97807
97808
97809
97810
97811
97812
97813
97814
97815
97816
97817
97818
97819
97820
97821
97822
    case TK_SELECT:
    case TK_EXISTS:  testcase( pExpr->op==TK_EXISTS );
#endif
    case TK_IN: {
      testcase( pExpr->op==TK_IN );
      if( ExprHasProperty(pExpr, EP_xIsSelect) ){
        int nRef = pNC->nRef;
        testcase( pNC->ncFlags & NC_IsCheck );
        testcase( pNC->ncFlags & NC_PartIdx );
        testcase( pNC->ncFlags & NC_IdxExpr );
        testcase( pNC->ncFlags & NC_GenCol );
        sqlite3ResolveNotValid(pParse, pNC, "subqueries",
                 NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);
        sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
        assert( pNC->nRef>=nRef );
        if( nRef!=pNC->nRef ){
          ExprSetProperty(pExpr, EP_VarSelect);
          pNC->ncFlags |= NC_VarSelect;
        }
      }
      break;
    }
    case TK_VARIABLE: {
      testcase( pNC->ncFlags & NC_IsCheck );
      testcase( pNC->ncFlags & NC_PartIdx );
      testcase( pNC->ncFlags & NC_IdxExpr );
      testcase( pNC->ncFlags & NC_GenCol );
      sqlite3ResolveNotValid(pParse, pNC, "parameters",
               NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);
      break;
    }
    case TK_IS:
    case TK_ISNOT: {
      Expr *pRight = sqlite3ExprSkipCollateAndLikely(pExpr->pRight);
      assert( !ExprHasProperty(pExpr, EP_Reduced) );
      /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
      ** and "x IS NOT FALSE". */
      if( pRight && pRight->op==TK_ID ){
        int rc = resolveExprStep(pWalker, pRight);
        if( rc==WRC_Abort ) return WRC_Abort;
        if( pRight->op==TK_TRUEFALSE ){
          pExpr->op2 = pExpr->op;
          pExpr->op = TK_TRUTH;
          return WRC_Continue;
        }
97050
97051
97052
97053
97054
97055
97056
97057
97058

97059
97060
97061
97062
97063
97064
97065
  int i;             /* Loop counter */

  UNUSED_PARAMETER(pParse);

  if( pE->op==TK_ID ){
    char *zCol = pE->u.zToken;
    for(i=0; i<pEList->nExpr; i++){
      char *zAs = pEList->a[i].zName;
      if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){

        return i+1;
      }
    }
  }
  return 0;
}








|
|
>







97881
97882
97883
97884
97885
97886
97887
97888
97889
97890
97891
97892
97893
97894
97895
97896
97897
  int i;             /* Loop counter */

  UNUSED_PARAMETER(pParse);

  if( pE->op==TK_ID ){
    char *zCol = pE->u.zToken;
    for(i=0; i<pEList->nExpr; i++){
      if( pEList->a[i].eEName==ENAME_NAME
       && sqlite3_stricmp(pEList->a[i].zEName, zCol)==0
      ){
        return i+1;
      }
    }
  }
  return 0;
}

97102
97103
97104
97105
97106
97107
97108
97109
97110
97111
97112
97113
97114
97115
97116
  nc.pParse = pParse;
  nc.pSrcList = pSelect->pSrc;
  nc.uNC.pEList = pEList;
  nc.ncFlags = NC_AllowAgg|NC_UEList;
  nc.nErr = 0;
  db = pParse->db;
  savedSuppErr = db->suppressErr;
  db->suppressErr = 1;
  rc = sqlite3ResolveExprNames(&nc, pE);
  db->suppressErr = savedSuppErr;
  if( rc ) return 0;

  /* Try to match the ORDER BY expression against an expression
  ** in the result set.  Return an 1-based index of the matching
  ** result-set entry.







|







97934
97935
97936
97937
97938
97939
97940
97941
97942
97943
97944
97945
97946
97947
97948
  nc.pParse = pParse;
  nc.pSrcList = pSelect->pSrc;
  nc.uNC.pEList = pEList;
  nc.ncFlags = NC_AllowAgg|NC_UEList;
  nc.nErr = 0;
  db = pParse->db;
  savedSuppErr = db->suppressErr;
  if( IN_RENAME_OBJECT==0 ) db->suppressErr = 1;
  rc = sqlite3ResolveExprNames(&nc, pE);
  db->suppressErr = savedSuppErr;
  if( rc ) return 0;

  /* Try to match the ORDER BY expression against an expression
  ** in the result set.  Return an 1-based index of the matching
  ** result-set entry.
97737
97738
97739
97740
97741
97742
97743


97744







97745





97746
97747













97748



97749
97750
97751
97752
97753
97754
97755
** list rather than a single expression.
*/
SQLITE_PRIVATE int sqlite3ResolveExprListNames( 
  NameContext *pNC,       /* Namespace to resolve expressions in. */
  ExprList *pList         /* The expression list to be analyzed. */
){
  int i;


  if( pList ){







    for(i=0; i<pList->nExpr; i++){





      if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
    }













  }



  return WRC_Continue;
}

/*
** Resolve all names in all expressions of a SELECT and in all
** decendents of the SELECT, including compounds off of p->pPrior,
** subqueries in expressions, and subqueries used as FROM clause







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

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







98569
98570
98571
98572
98573
98574
98575
98576
98577
98578
98579
98580
98581
98582
98583
98584
98585
98586
98587
98588
98589
98590
98591
98592
98593
98594
98595
98596
98597
98598
98599
98600
98601
98602
98603
98604
98605
98606
98607
98608
98609
98610
98611
98612
98613
98614
98615
98616
98617
** list rather than a single expression.
*/
SQLITE_PRIVATE int sqlite3ResolveExprListNames( 
  NameContext *pNC,       /* Namespace to resolve expressions in. */
  ExprList *pList         /* The expression list to be analyzed. */
){
  int i;
  int savedHasAgg = 0;
  Walker w;
  if( pList==0 ) return WRC_Continue;
  w.pParse = pNC->pParse;
  w.xExprCallback = resolveExprStep;
  w.xSelectCallback = resolveSelectStep;
  w.xSelectCallback2 = 0;
  w.u.pNC = pNC;
  savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
  pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
  for(i=0; i<pList->nExpr; i++){
    Expr *pExpr = pList->a[i].pExpr;
    if( pExpr==0 ) continue;
#if SQLITE_MAX_EXPR_DEPTH>0
    w.pParse->nHeight += pExpr->nHeight;
    if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
      return WRC_Abort;
    }
#endif
    sqlite3WalkExpr(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
    w.pParse->nHeight -= pExpr->nHeight;
#endif
    assert( EP_Agg==NC_HasAgg );
    assert( EP_Win==NC_HasWin );
    testcase( pNC->ncFlags & NC_HasAgg );
    testcase( pNC->ncFlags & NC_HasWin );
    if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin) ){
      ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) );
      savedHasAgg |= pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
      pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
    }
    if( pNC->nErr>0 || w.pParse->nErr>0 ) return WRC_Abort;
  }
  pNC->ncFlags |= savedHasAgg;
  return WRC_Continue;
}

/*
** Resolve all names in all expressions of a SELECT and in all
** decendents of the SELECT, including compounds off of p->pPrior,
** subqueries in expressions, and subqueries used as FROM clause
97812
97813
97814
97815
97816
97817
97818





97819
97820
97821
97822
97823
97824
97825
  memset(&sNC, 0, sizeof(sNC));
  memset(&sSrc, 0, sizeof(sSrc));
  if( pTab ){
    sSrc.nSrc = 1;
    sSrc.a[0].zName = pTab->zName;
    sSrc.a[0].pTab = pTab;
    sSrc.a[0].iCursor = -1;





  }
  sNC.pParse = pParse;
  sNC.pSrcList = &sSrc;
  sNC.ncFlags = type | NC_IsDDL;
  if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc;
  if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList);
  return rc;







>
>
>
>
>







98674
98675
98676
98677
98678
98679
98680
98681
98682
98683
98684
98685
98686
98687
98688
98689
98690
98691
98692
  memset(&sNC, 0, sizeof(sNC));
  memset(&sSrc, 0, sizeof(sSrc));
  if( pTab ){
    sSrc.nSrc = 1;
    sSrc.a[0].zName = pTab->zName;
    sSrc.a[0].pTab = pTab;
    sSrc.a[0].iCursor = -1;
    if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
      /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
      ** schema elements */
      type |= NC_FromDDL;
    }
  }
  sNC.pParse = pParse;
  sNC.pSrcList = &sSrc;
  sNC.ncFlags = type | NC_IsDDL;
  if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc;
  if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList);
  return rc;
97867
97868
97869
97870
97871
97872
97873
97874
97875
97876
97877
97878
97879
97880
97881
** have an affinity:
**
** CREATE TABLE t1(a);
** SELECT * FROM t1 WHERE a;
** SELECT a AS b FROM t1 WHERE b;
** SELECT * FROM t1 WHERE (select a from t1);
*/
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
  int op;
  while( ExprHasProperty(pExpr, EP_Skip) ){
    assert( pExpr->op==TK_COLLATE );
    pExpr = pExpr->pLeft;
    assert( pExpr!=0 );
  }
  op = pExpr->op;







|







98734
98735
98736
98737
98738
98739
98740
98741
98742
98743
98744
98745
98746
98747
98748
** have an affinity:
**
** CREATE TABLE t1(a);
** SELECT * FROM t1 WHERE a;
** SELECT a AS b FROM t1 WHERE b;
** SELECT * FROM t1 WHERE (select a from t1);
*/
SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
  int op;
  while( ExprHasProperty(pExpr, EP_Skip) ){
    assert( pExpr->op==TK_COLLATE );
    pExpr = pExpr->pLeft;
    assert( pExpr!=0 );
  }
  op = pExpr->op;
97977
97978
97979
97980
97981
97982
97983
97984
97985
97986
97987
97988
97989
97990
97991
97992
97993
97994
** default collation if pExpr has no defined collation.
**
** The collating sequence might be determined by a COLLATE operator
** or by the presence of a column with a defined collating sequence.
** COLLATE operators take first precedence.  Left operands take
** precedence over right operands.
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
  sqlite3 *db = pParse->db;
  CollSeq *pColl = 0;
  Expr *p = pExpr;
  while( p ){
    int op = p->op;
    if( op==TK_REGISTER ) op = p->op2;
    if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER)
     && p->y.pTab!=0
    ){
      /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally







|


|







98844
98845
98846
98847
98848
98849
98850
98851
98852
98853
98854
98855
98856
98857
98858
98859
98860
98861
** default collation if pExpr has no defined collation.
**
** The collating sequence might be determined by a COLLATE operator
** or by the presence of a column with a defined collating sequence.
** COLLATE operators take first precedence.  Left operands take
** precedence over right operands.
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
  sqlite3 *db = pParse->db;
  CollSeq *pColl = 0;
  const Expr *p = pExpr;
  while( p ){
    int op = p->op;
    if( op==TK_REGISTER ) op = p->op2;
    if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER)
     && p->y.pTab!=0
    ){
      /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally
98049
98050
98051
98052
98053
98054
98055
98056
98057
98058
98059
98060
98061
98062
98063
98064
98065
98066
98067
98068
98069
98070
98071
98072
98073
98074
98075
98076
98077
98078
98079
98080
98081
98082
98083
98084
** defautl collation sequence.
**
** See also: sqlite3ExprCollSeq()
**
** The sqlite3ExprCollSeq() routine works the same except that it
** returns NULL if there is no defined collation.
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){
  CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
  if( p==0 ) p = pParse->db->pDfltColl;
  assert( p!=0 );
  return p;
}

/*
** Return TRUE if the two expressions have equivalent collating sequences.
*/
SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
  CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
  CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
  return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
}

/*
** pExpr is an operand of a comparison operator.  aff2 is the
** type affinity of the other operand.  This routine returns the
** type affinity that should be used for the comparison operator.
*/
SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){
  char aff1 = sqlite3ExprAffinity(pExpr);
  if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){
    /* Both sides of the comparison are columns. If one has numeric
    ** affinity, use that. Otherwise use no affinity.
    */
    if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){
      return SQLITE_AFF_NUMERIC;







|









|










|







98916
98917
98918
98919
98920
98921
98922
98923
98924
98925
98926
98927
98928
98929
98930
98931
98932
98933
98934
98935
98936
98937
98938
98939
98940
98941
98942
98943
98944
98945
98946
98947
98948
98949
98950
98951
** defautl collation sequence.
**
** See also: sqlite3ExprCollSeq()
**
** The sqlite3ExprCollSeq() routine works the same except that it
** returns NULL if there is no defined collation.
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr){
  CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
  if( p==0 ) p = pParse->db->pDfltColl;
  assert( p!=0 );
  return p;
}

/*
** Return TRUE if the two expressions have equivalent collating sequences.
*/
SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){
  CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
  CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
  return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
}

/*
** pExpr is an operand of a comparison operator.  aff2 is the
** type affinity of the other operand.  This routine returns the
** type affinity that should be used for the comparison operator.
*/
SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2){
  char aff1 = sqlite3ExprAffinity(pExpr);
  if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){
    /* Both sides of the comparison are columns. If one has numeric
    ** affinity, use that. Otherwise use no affinity.
    */
    if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){
      return SQLITE_AFF_NUMERIC;
98092
98093
98094
98095
98096
98097
98098
98099
98100
98101
98102
98103
98104
98105
98106
  }
}

/*
** pExpr is a comparison operator.  Return the type affinity that should
** be applied to both operands prior to doing the comparison.
*/
static char comparisonAffinity(Expr *pExpr){
  char aff;
  assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT ||
          pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE ||
          pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT );
  assert( pExpr->pLeft );
  aff = sqlite3ExprAffinity(pExpr->pLeft);
  if( pExpr->pRight ){







|







98959
98960
98961
98962
98963
98964
98965
98966
98967
98968
98969
98970
98971
98972
98973
  }
}

/*
** pExpr is a comparison operator.  Return the type affinity that should
** be applied to both operands prior to doing the comparison.
*/
static char comparisonAffinity(const Expr *pExpr){
  char aff;
  assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT ||
          pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE ||
          pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT );
  assert( pExpr->pLeft );
  aff = sqlite3ExprAffinity(pExpr->pLeft);
  if( pExpr->pRight ){
98115
98116
98117
98118
98119
98120
98121
98122
98123
98124
98125
98126
98127
98128
98129
98130
98131
98132
98133
98134
98135
98136
98137




98138
98139
98140
98141
98142
98143
98144
98145
98146
98147
98148
98149
98150
98151
98152
98153
98154
98155
98156
98157
98158
98159
98160
98161
98162
98163
98164
98165

/*
** pExpr is a comparison expression, eg. '=', '<', IN(...) etc.
** idx_affinity is the affinity of an indexed column. Return true
** if the index with affinity idx_affinity may be used to implement
** the comparison in pExpr.
*/
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
  char aff = comparisonAffinity(pExpr);
  if( aff<SQLITE_AFF_TEXT ){
    return 1;
  }
  if( aff==SQLITE_AFF_TEXT ){
    return idx_affinity==SQLITE_AFF_TEXT;
  }
  return sqlite3IsNumericAffinity(idx_affinity);
}

/*
** Return the P5 value that should be used for a binary comparison
** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
*/
static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){




  u8 aff = (char)sqlite3ExprAffinity(pExpr2);
  aff = (u8)sqlite3CompareAffinity(pExpr1, aff) | (u8)jumpIfNull;
  return aff;
}

/*
** Return a pointer to the collation sequence that should be used by
** a binary comparison operator comparing pLeft and pRight.
**
** If the left hand expression has a collating sequence type, then it is
** used. Otherwise the collation sequence for the right hand expression
** is used, or the default (BINARY) if neither expression has a collating
** type.
**
** Argument pRight (but not pLeft) may be a null pointer. In this case,
** it is not considered.
*/
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
  Parse *pParse, 
  Expr *pLeft, 
  Expr *pRight
){
  CollSeq *pColl;
  assert( pLeft );
  if( pLeft->flags & EP_Collate ){
    pColl = sqlite3ExprCollSeq(pParse, pLeft);
  }else if( pRight && (pRight->flags & EP_Collate)!=0 ){
    pColl = sqlite3ExprCollSeq(pParse, pRight);







|














|
>
>
>
>



















|
|







98982
98983
98984
98985
98986
98987
98988
98989
98990
98991
98992
98993
98994
98995
98996
98997
98998
98999
99000
99001
99002
99003
99004
99005
99006
99007
99008
99009
99010
99011
99012
99013
99014
99015
99016
99017
99018
99019
99020
99021
99022
99023
99024
99025
99026
99027
99028
99029
99030
99031
99032
99033
99034
99035
99036

/*
** pExpr is a comparison expression, eg. '=', '<', IN(...) etc.
** idx_affinity is the affinity of an indexed column. Return true
** if the index with affinity idx_affinity may be used to implement
** the comparison in pExpr.
*/
SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity){
  char aff = comparisonAffinity(pExpr);
  if( aff<SQLITE_AFF_TEXT ){
    return 1;
  }
  if( aff==SQLITE_AFF_TEXT ){
    return idx_affinity==SQLITE_AFF_TEXT;
  }
  return sqlite3IsNumericAffinity(idx_affinity);
}

/*
** Return the P5 value that should be used for a binary comparison
** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
*/
static u8 binaryCompareP5(
  const Expr *pExpr1,   /* Left operand */
  const Expr *pExpr2,   /* Right operand */
  int jumpIfNull        /* Extra flags added to P5 */
){
  u8 aff = (char)sqlite3ExprAffinity(pExpr2);
  aff = (u8)sqlite3CompareAffinity(pExpr1, aff) | (u8)jumpIfNull;
  return aff;
}

/*
** Return a pointer to the collation sequence that should be used by
** a binary comparison operator comparing pLeft and pRight.
**
** If the left hand expression has a collating sequence type, then it is
** used. Otherwise the collation sequence for the right hand expression
** is used, or the default (BINARY) if neither expression has a collating
** type.
**
** Argument pRight (but not pLeft) may be a null pointer. In this case,
** it is not considered.
*/
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
  Parse *pParse, 
  const Expr *pLeft, 
  const Expr *pRight
){
  CollSeq *pColl;
  assert( pLeft );
  if( pLeft->flags & EP_Collate ){
    pColl = sqlite3ExprCollSeq(pParse, pLeft);
  }else if( pRight && (pRight->flags & EP_Collate)!=0 ){
    pColl = sqlite3ExprCollSeq(pParse, pRight);
98176
98177
98178
98179
98180
98181
98182
98183
98184
98185
98186
98187
98188
98189
98190
** appropriate for the comparison operator.
**
** This is normally just a wrapper around sqlite3BinaryCompareCollSeq().
** However, if the OP_Commuted flag is set, then the order of the operands
** is reversed in the sqlite3BinaryCompareCollSeq() call so that the
** correct collating sequence is found.
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, Expr *p){
  if( ExprHasProperty(p, EP_Commuted) ){
    return sqlite3BinaryCompareCollSeq(pParse, p->pRight, p->pLeft);
  }else{
    return sqlite3BinaryCompareCollSeq(pParse, p->pLeft, p->pRight);
  }
}








|







99047
99048
99049
99050
99051
99052
99053
99054
99055
99056
99057
99058
99059
99060
99061
** appropriate for the comparison operator.
**
** This is normally just a wrapper around sqlite3BinaryCompareCollSeq().
** However, if the OP_Commuted flag is set, then the order of the operands
** is reversed in the sqlite3BinaryCompareCollSeq() call so that the
** correct collating sequence is found.
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, const Expr *p){
  if( ExprHasProperty(p, EP_Commuted) ){
    return sqlite3BinaryCompareCollSeq(pParse, p->pRight, p->pLeft);
  }else{
    return sqlite3BinaryCompareCollSeq(pParse, p->pLeft, p->pRight);
  }
}

98201
98202
98203
98204
98205
98206
98207

98208
98209
98210
98211
98212
98213
98214
  int jumpIfNull,   /* If true, jump if either operand is NULL */
  int isCommuted    /* The comparison has been commuted */
){
  int p5;
  int addr;
  CollSeq *p4;


  if( isCommuted ){
    p4 = sqlite3BinaryCompareCollSeq(pParse, pRight, pLeft);
  }else{
    p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
  }
  p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
  addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,







>







99072
99073
99074
99075
99076
99077
99078
99079
99080
99081
99082
99083
99084
99085
99086
  int jumpIfNull,   /* If true, jump if either operand is NULL */
  int isCommuted    /* The comparison has been commuted */
){
  int p5;
  int addr;
  CollSeq *p4;

  if( pParse->nErr ) return 0;
  if( isCommuted ){
    p4 = sqlite3BinaryCompareCollSeq(pParse, pRight, pLeft);
  }else{
    p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
  }
  p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
  addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
98418
98419
98420
98421
98422
98423
98424


98425
98426
98427
98428
98429
98430
98431
  int i;
  int regLeft = 0;
  int regRight = 0;
  u8 opx = op;
  int addrDone = sqlite3VdbeMakeLabel(pParse);
  int isCommuted = ExprHasProperty(pExpr,EP_Commuted);



  if( nLeft!=sqlite3ExprVectorSize(pRight) ){
    sqlite3ErrorMsg(pParse, "row value misused");
    return;
  }
  assert( pExpr->op==TK_EQ || pExpr->op==TK_NE 
       || pExpr->op==TK_IS || pExpr->op==TK_ISNOT 
       || pExpr->op==TK_LT || pExpr->op==TK_GT 







>
>







99290
99291
99292
99293
99294
99295
99296
99297
99298
99299
99300
99301
99302
99303
99304
99305
  int i;
  int regLeft = 0;
  int regRight = 0;
  u8 opx = op;
  int addrDone = sqlite3VdbeMakeLabel(pParse);
  int isCommuted = ExprHasProperty(pExpr,EP_Commuted);

  assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
  if( pParse->nErr ) return;
  if( nLeft!=sqlite3ExprVectorSize(pRight) ){
    sqlite3ErrorMsg(pParse, "row value misused");
    return;
  }
  assert( pExpr->op==TK_EQ || pExpr->op==TK_NE 
       || pExpr->op==TK_IS || pExpr->op==TK_ISNOT 
       || pExpr->op==TK_LT || pExpr->op==TK_GT 
98756
98757
98758
98759
98760
98761
98762
98763


98764
98765
98766
98767
98768
98769
98770
98771
98772
*/
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
  sqlite3 *db = pParse->db;
  if( pLeft==0  ){
    return pRight;
  }else if( pRight==0 ){
    return pLeft;
  }else if( ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight) ){


    sqlite3ExprUnmapAndDelete(pParse, pLeft);
    sqlite3ExprUnmapAndDelete(pParse, pRight);
    return sqlite3Expr(db, TK_INTEGER, "0");
  }else{
    return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
  }
}

/*







|
>
>
|
|







99630
99631
99632
99633
99634
99635
99636
99637
99638
99639
99640
99641
99642
99643
99644
99645
99646
99647
99648
*/
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
  sqlite3 *db = pParse->db;
  if( pLeft==0  ){
    return pRight;
  }else if( pRight==0 ){
    return pLeft;
  }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight)) 
         && !IN_RENAME_OBJECT
  ){
    sqlite3ExprDelete(db, pLeft);
    sqlite3ExprDelete(db, pRight);
    return sqlite3Expr(db, TK_INTEGER, "0");
  }else{
    return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
  }
}

/*
98793
98794
98795
98796
98797
98798
98799


































98800
98801
98802
98803
98804
98805
98806
  pNew->x.pList = pList;
  ExprSetProperty(pNew, EP_HasFunc);
  assert( !ExprHasProperty(pNew, EP_xIsSelect) );
  sqlite3ExprSetHeightAndFlags(pParse, pNew);
  if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct);
  return pNew;
}



































/*
** Assign a variable number to an expression that encodes a wildcard
** in the original SQL statement.  
**
** Wildcards consisting of a single "?" are assigned the next sequential
** variable number.







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







99669
99670
99671
99672
99673
99674
99675
99676
99677
99678
99679
99680
99681
99682
99683
99684
99685
99686
99687
99688
99689
99690
99691
99692
99693
99694
99695
99696
99697
99698
99699
99700
99701
99702
99703
99704
99705
99706
99707
99708
99709
99710
99711
99712
99713
99714
99715
99716
  pNew->x.pList = pList;
  ExprSetProperty(pNew, EP_HasFunc);
  assert( !ExprHasProperty(pNew, EP_xIsSelect) );
  sqlite3ExprSetHeightAndFlags(pParse, pNew);
  if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct);
  return pNew;
}

/*
** Check to see if a function is usable according to current access
** rules:
**
**    SQLITE_FUNC_DIRECT    -     Only usable from top-level SQL
**
**    SQLITE_FUNC_UNSAFE    -     Usable if TRUSTED_SCHEMA or from
**                                top-level SQL
**
** If the function is not usable, create an error.
*/
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(
  Parse *pParse,         /* Parsing and code generating context */
  Expr *pExpr,           /* The function invocation */
  FuncDef *pDef          /* The function being invoked */
){
  assert( !IN_RENAME_OBJECT );
  assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 );
  if( ExprHasProperty(pExpr, EP_FromDDL) ){
    if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
     || (pParse->db->flags & SQLITE_TrustedSchema)==0
    ){
      /* Functions prohibited in triggers and views if:
      **     (1) tagged with SQLITE_DIRECTONLY
      **     (2) not tagged with SQLITE_INNOCUOUS (which means it
      **         is tagged with SQLITE_FUNC_UNSAFE) and 
      **         SQLITE_DBCONFIG_TRUSTED_SCHEMA is off (meaning
      **         that the schema is possibly tainted).
      */
      sqlite3ErrorMsg(pParse, "unsafe use of %s()", pDef->zName);
    }
  }
}

/*
** Assign a variable number to an expression that encodes a wildcard
** in the original SQL statement.  
**
** Wildcards consisting of a single "?" are assigned the next sequential
** variable number.
98993
98994
98995
98996
98997
98998
98999
99000
99001
99002
99003
99004
99005
99006
99007
#endif
  ){
    nSize = EXPR_FULLSIZE;
  }else{
    assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
    assert( !ExprHasProperty(p, EP_FromJoin) ); 
    assert( !ExprHasProperty(p, EP_MemToken) );
    assert( !ExprHasProperty(p, EP_NoReduce) );
    if( p->pLeft || p->x.pList ){
      nSize = EXPR_REDUCEDSIZE | EP_Reduced;
    }else{
      assert( p->pRight==0 );
      nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
    }
  }







|







99903
99904
99905
99906
99907
99908
99909
99910
99911
99912
99913
99914
99915
99916
99917
#endif
  ){
    nSize = EXPR_FULLSIZE;
  }else{
    assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
    assert( !ExprHasProperty(p, EP_FromJoin) ); 
    assert( !ExprHasProperty(p, EP_MemToken) );
    assert( !ExprHasVVAProperty(p, EP_NoReduce) );
    if( p->pLeft || p->x.pList ){
      nSize = EXPR_REDUCEDSIZE | EP_Reduced;
    }else{
      assert( p->pRight==0 );
      nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
    }
  }
99098
99099
99100
99101
99102
99103
99104




99105
99106
99107
99108
99109
99110
99111
      }
    }

    /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
    pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
    pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
    pNew->flags |= staticFlag;





    /* Copy the p->u.zToken string, if any. */
    if( nToken ){
      char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
      memcpy(zToken, p->u.zToken, nToken);
    }








>
>
>
>







100008
100009
100010
100011
100012
100013
100014
100015
100016
100017
100018
100019
100020
100021
100022
100023
100024
100025
      }
    }

    /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
    pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
    pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
    pNew->flags |= staticFlag;
    ExprClearVVAProperties(pNew);
    if( dupFlags ){
      ExprSetVVAProperty(pNew, EP_Immutable);
    }

    /* Copy the p->u.zToken string, if any. */
    if( nToken ){
      char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
      memcpy(zToken, p->u.zToken, nToken);
    }

99261
99262
99263
99264
99265
99266
99267
99268
99269
99270

99271
99272
99273
99274
99275
99276
99277
99278
99279
99280
        assert( i>0 );
        assert( pItem[-1].pExpr!=0 );
        assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 );
        assert( pPriorSelectCol==pItem[-1].pExpr->pLeft );
        pNewExpr->pLeft = pPriorSelectCol;
      }
    }
    pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
    pItem->sortFlags = pOldItem->sortFlags;

    pItem->done = 0;
    pItem->bNulls = pOldItem->bNulls;
    pItem->bSpanIsTab = pOldItem->bSpanIsTab;
    pItem->bSorterRef = pOldItem->bSorterRef;
    pItem->u = pOldItem->u;
  }
  return pNew;
}

/*







|
<

>


<







100175
100176
100177
100178
100179
100180
100181
100182

100183
100184
100185
100186

100187
100188
100189
100190
100191
100192
100193
        assert( i>0 );
        assert( pItem[-1].pExpr!=0 );
        assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 );
        assert( pPriorSelectCol==pItem[-1].pExpr->pLeft );
        pNewExpr->pLeft = pPriorSelectCol;
      }
    }
    pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);

    pItem->sortFlags = pOldItem->sortFlags;
    pItem->eEName = pOldItem->eEName;
    pItem->done = 0;
    pItem->bNulls = pOldItem->bNulls;

    pItem->bSorterRef = pOldItem->bSorterRef;
    pItem->u = pOldItem->u;
  }
  return pNew;
}

/*
99433
99434
99435
99436
99437
99438
99439
99440
99441
99442
99443
99444
99445
99446
99447
99448
99449
         sizeof(*pList)+(2*(sqlite3_int64)pList->nExpr-1)*sizeof(pList->a[0]));
    if( pNew==0 ){
      goto no_mem;
    }
    pList = pNew;
  }
  pItem = &pList->a[pList->nExpr++];
  assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) );
  assert( offsetof(struct ExprList_item,pExpr)==0 );
  memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName));
  pItem->pExpr = pExpr;
  return pList;

no_mem:     
  /* Avoid leaking memory if malloc has failed. */
  sqlite3ExprDelete(db, pExpr);
  sqlite3ExprListDelete(db, pList);







|

|







100346
100347
100348
100349
100350
100351
100352
100353
100354
100355
100356
100357
100358
100359
100360
100361
100362
         sizeof(*pList)+(2*(sqlite3_int64)pList->nExpr-1)*sizeof(pList->a[0]));
    if( pNew==0 ){
      goto no_mem;
    }
    pList = pNew;
  }
  pItem = &pList->a[pList->nExpr++];
  assert( offsetof(struct ExprList_item,zEName)==sizeof(pItem->pExpr) );
  assert( offsetof(struct ExprList_item,pExpr)==0 );
  memset(&pItem->zEName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zEName));
  pItem->pExpr = pExpr;
  return pList;

no_mem:     
  /* Avoid leaking memory if malloc has failed. */
  sqlite3ExprDelete(db, pExpr);
  sqlite3ExprListDelete(db, pList);
99492
99493
99494
99495
99496
99497
99498
99499
99500
99501
99502
99503
99504
99505
99506
    assert( pSubExpr!=0 || db->mallocFailed );
    assert( pSubExpr==0 || pSubExpr->iTable==0 );
    if( pSubExpr==0 ) continue;
    pSubExpr->iTable = pColumns->nId;
    pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
    if( pList ){
      assert( pList->nExpr==iFirst+i+1 );
      pList->a[pList->nExpr-1].zName = pColumns->a[i].zName;
      pColumns->a[i].zName = 0;
    }
  }

  if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){
    Expr *pFirst = pList->a[iFirst].pExpr;
    assert( pFirst!=0 );







|







100405
100406
100407
100408
100409
100410
100411
100412
100413
100414
100415
100416
100417
100418
100419
    assert( pSubExpr!=0 || db->mallocFailed );
    assert( pSubExpr==0 || pSubExpr->iTable==0 );
    if( pSubExpr==0 ) continue;
    pSubExpr->iTable = pColumns->nId;
    pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
    if( pList ){
      assert( pList->nExpr==iFirst+i+1 );
      pList->a[pList->nExpr-1].zEName = pColumns->a[i].zName;
      pColumns->a[i].zName = 0;
    }
  }

  if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){
    Expr *pFirst = pList->a[iFirst].pExpr;
    assert( pFirst!=0 );
99552
99553
99554
99555
99556
99557
99558
99559
99560
99561
99562
99563
99564
99565
99566
99567
99568
99569
99570
99571
99572

99573
99574
99575
99576
99577

99578
99579




99580
99581

99582
99583
99584
99585
99586
99587
99588
    if( iSortOrder!=eNulls ){
      pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
    }
  }
}

/*
** Set the ExprList.a[].zName element of the most recently added item
** on the expression list.
**
** pList might be NULL following an OOM error.  But pName should never be
** NULL.  If a memory allocation fails, the pParse->db->mallocFailed flag
** is set.
*/
SQLITE_PRIVATE void sqlite3ExprListSetName(
  Parse *pParse,          /* Parsing context */
  ExprList *pList,        /* List to which to add the span. */
  Token *pName,           /* Name to be added */
  int dequote             /* True to cause the name to be dequoted */
){
  assert( pList!=0 || pParse->db->mallocFailed!=0 );

  if( pList ){
    struct ExprList_item *pItem;
    assert( pList->nExpr>0 );
    pItem = &pList->a[pList->nExpr-1];
    assert( pItem->zName==0 );

    pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
    if( dequote ) sqlite3Dequote(pItem->zName);




    if( IN_RENAME_OBJECT ){
      sqlite3RenameTokenMap(pParse, (void*)pItem->zName, pName);

    }
  }
}

/*
** Set the ExprList.a[].zSpan element of the most recently added item
** on the expression list.







|













>




|
>
|
|
>
>
>
>
|
|
>







100465
100466
100467
100468
100469
100470
100471
100472
100473
100474
100475
100476
100477
100478
100479
100480
100481
100482
100483
100484
100485
100486
100487
100488
100489
100490
100491
100492
100493
100494
100495
100496
100497
100498
100499
100500
100501
100502
100503
100504
100505
100506
100507
100508
    if( iSortOrder!=eNulls ){
      pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
    }
  }
}

/*
** Set the ExprList.a[].zEName element of the most recently added item
** on the expression list.
**
** pList might be NULL following an OOM error.  But pName should never be
** NULL.  If a memory allocation fails, the pParse->db->mallocFailed flag
** is set.
*/
SQLITE_PRIVATE void sqlite3ExprListSetName(
  Parse *pParse,          /* Parsing context */
  ExprList *pList,        /* List to which to add the span. */
  Token *pName,           /* Name to be added */
  int dequote             /* True to cause the name to be dequoted */
){
  assert( pList!=0 || pParse->db->mallocFailed!=0 );
  assert( pParse->eParseMode!=PARSE_MODE_UNMAP || dequote==0 );
  if( pList ){
    struct ExprList_item *pItem;
    assert( pList->nExpr>0 );
    pItem = &pList->a[pList->nExpr-1];
    assert( pItem->zEName==0 );
    assert( pItem->eEName==ENAME_NAME );
    pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
    if( dequote ){
      /* If dequote==0, then pName->z does not point to part of a DDL
      ** statement handled by the parser. And so no token need be added
      ** to the token-map.  */
      sqlite3Dequote(pItem->zEName);
      if( IN_RENAME_OBJECT ){
        sqlite3RenameTokenMap(pParse, (void*)pItem->zEName, pName);
      }
    }
  }
}

/*
** Set the ExprList.a[].zSpan element of the most recently added item
** on the expression list.
99598
99599
99600
99601
99602
99603
99604
99605
99606


99607
99608
99609
99610
99611
99612
99613
  const char *zEnd        /* End of the span */
){
  sqlite3 *db = pParse->db;
  assert( pList!=0 || db->mallocFailed!=0 );
  if( pList ){
    struct ExprList_item *pItem = &pList->a[pList->nExpr-1];
    assert( pList->nExpr>0 );
    sqlite3DbFree(db, pItem->zSpan);
    pItem->zSpan = sqlite3DbSpanDup(db, zStart, zEnd);


  }
}

/*
** If the expression list pEList contains more than iLimit elements,
** leave an error message in pParse.
*/







|
|
>
>







100518
100519
100520
100521
100522
100523
100524
100525
100526
100527
100528
100529
100530
100531
100532
100533
100534
100535
  const char *zEnd        /* End of the span */
){
  sqlite3 *db = pParse->db;
  assert( pList!=0 || db->mallocFailed!=0 );
  if( pList ){
    struct ExprList_item *pItem = &pList->a[pList->nExpr-1];
    assert( pList->nExpr>0 );
    if( pItem->zEName==0 ){
      pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd);
      pItem->eEName = ENAME_SPAN;
    }
  }
}

/*
** If the expression list pEList contains more than iLimit elements,
** leave an error message in pParse.
*/
99629
99630
99631
99632
99633
99634
99635
99636
99637
99638
99639
99640
99641
99642
99643
99644
*/
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
  int i = pList->nExpr;
  struct ExprList_item *pItem =  pList->a;
  assert( pList->nExpr>0 );
  do{
    sqlite3ExprDelete(db, pItem->pExpr);
    sqlite3DbFree(db, pItem->zName);
    sqlite3DbFree(db, pItem->zSpan);
    pItem++;
  }while( --i>0 );
  sqlite3DbFreeNN(db, pList);
}
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
  if( pList ) exprListDeleteNN(db, pList);
}







|
<







100551
100552
100553
100554
100555
100556
100557
100558

100559
100560
100561
100562
100563
100564
100565
*/
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
  int i = pList->nExpr;
  struct ExprList_item *pItem =  pList->a;
  assert( pList->nExpr>0 );
  do{
    sqlite3ExprDelete(db, pItem->pExpr);
    sqlite3DbFree(db, pItem->zEName);

    pItem++;
  }while( --i>0 );
  sqlite3DbFreeNN(db, pList);
}
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
  if( pList ) exprListDeleteNN(db, pList);
}
99667
99668
99669
99670
99671
99672
99673















99674
99675
99676
99677
99678
99679
99680

99681
99682
99683
99684
99685
99686
99687
99688
99689
99690
99691
99692
99693
99694
** This callback is used by multiple expression walkers.
*/
SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){
  UNUSED_PARAMETER(NotUsed);
  pWalker->eCode = 0;
  return WRC_Abort;
}
















/*
** If the input expression is an ID with the name "true" or "false"
** then convert it into an TK_TRUEFALSE term.  Return non-zero if
** the conversion happened, and zero if the expression is unaltered.
*/
SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){

  assert( pExpr->op==TK_ID || pExpr->op==TK_STRING );
  if( !ExprHasProperty(pExpr, EP_Quoted)
   && (sqlite3StrICmp(pExpr->u.zToken, "true")==0
       || sqlite3StrICmp(pExpr->u.zToken, "false")==0)
  ){
    pExpr->op = TK_TRUEFALSE;
    ExprSetProperty(pExpr, pExpr->u.zToken[4]==0 ? EP_IsTrue : EP_IsFalse);
    return 1;
  }
  return 0;
}

/*
** The argument must be a TK_TRUEFALSE Expr node.  Return 1 if it is TRUE







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







>


|
<


|







100588
100589
100590
100591
100592
100593
100594
100595
100596
100597
100598
100599
100600
100601
100602
100603
100604
100605
100606
100607
100608
100609
100610
100611
100612
100613
100614
100615
100616
100617
100618
100619
100620

100621
100622
100623
100624
100625
100626
100627
100628
100629
100630
** This callback is used by multiple expression walkers.
*/
SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){
  UNUSED_PARAMETER(NotUsed);
  pWalker->eCode = 0;
  return WRC_Abort;
}

/*
** Check the input string to see if it is "true" or "false" (in any case).
**
**       If the string is....           Return
**         "true"                         EP_IsTrue
**         "false"                        EP_IsFalse
**         anything else                  0
*/
SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char *zIn){
  if( sqlite3StrICmp(zIn, "true")==0  ) return EP_IsTrue;
  if( sqlite3StrICmp(zIn, "false")==0 ) return EP_IsFalse;
  return 0;
}


/*
** If the input expression is an ID with the name "true" or "false"
** then convert it into an TK_TRUEFALSE term.  Return non-zero if
** the conversion happened, and zero if the expression is unaltered.
*/
SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){
  u32 v;
  assert( pExpr->op==TK_ID || pExpr->op==TK_STRING );
  if( !ExprHasProperty(pExpr, EP_Quoted)
   && (v = sqlite3IsTrueOrFalse(pExpr->u.zToken))!=0

  ){
    pExpr->op = TK_TRUEFALSE;
    ExprSetProperty(pExpr, v);
    return 1;
  }
  return 0;
}

/*
** The argument must be a TK_TRUEFALSE Expr node.  Return 1 if it is TRUE
99742
99743
99744
99745
99746
99747
99748
99749
99750

99751
99752
99753
99754
99755
99756
99757
99758
99759
99760
99761
99762
99763
99764
99765
99766
99767
99768
99769
99770
99771
99772
99773



99774
99775
99776
99777
99778
99779
99780
**     sqlite3ExprIsConstantNotJoin()           pWalker->eCode==2
**     sqlite3ExprIsTableConstant()             pWalker->eCode==3
**     sqlite3ExprIsConstantOrFunction()        pWalker->eCode==4 or 5
**
** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
** is found to not be a constant.
**
** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions
** in a CREATE TABLE statement.  The Walker.eCode value is 5 when parsing

** an existing schema and 4 when processing a new statement.  A bound
** parameter raises an error for new statements, but is silently converted
** to NULL for existing schemas.  This allows sqlite_master tables that 
** contain a bound parameter because they were generated by older versions
** of SQLite to be parsed by newer versions of SQLite without raising a
** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){

  /* If pWalker->eCode is 2 then any term of the expression that comes from
  ** the ON or USING clauses of a left join disqualifies the expression
  ** from being considered constant. */
  if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
    pWalker->eCode = 0;
    return WRC_Abort;
  }

  switch( pExpr->op ){
    /* Consider functions to be constant if all their arguments are constant
    ** and either pWalker->eCode==4 or 5 or the function has the
    ** SQLITE_FUNC_CONST flag. */
    case TK_FUNCTION:
      if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){



        return WRC_Continue;
      }else{
        pWalker->eCode = 0;
        return WRC_Abort;
      }
    case TK_ID:
      /* Convert "true" or "false" in a DEFAULT clause into the







|
|
>
|
|




















|
>
>
>







100678
100679
100680
100681
100682
100683
100684
100685
100686
100687
100688
100689
100690
100691
100692
100693
100694
100695
100696
100697
100698
100699
100700
100701
100702
100703
100704
100705
100706
100707
100708
100709
100710
100711
100712
100713
100714
100715
100716
100717
100718
100719
100720
**     sqlite3ExprIsConstantNotJoin()           pWalker->eCode==2
**     sqlite3ExprIsTableConstant()             pWalker->eCode==3
**     sqlite3ExprIsConstantOrFunction()        pWalker->eCode==4 or 5
**
** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
** is found to not be a constant.
**
** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT
** expressions in a CREATE TABLE statement.  The Walker.eCode value is 5
** when parsing an existing schema out of the sqlite_master table and 4
** when processing a new CREATE TABLE statement.  A bound parameter raises
** an error for new statements, but is silently converted
** to NULL for existing schemas.  This allows sqlite_master tables that 
** contain a bound parameter because they were generated by older versions
** of SQLite to be parsed by newer versions of SQLite without raising a
** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){

  /* If pWalker->eCode is 2 then any term of the expression that comes from
  ** the ON or USING clauses of a left join disqualifies the expression
  ** from being considered constant. */
  if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
    pWalker->eCode = 0;
    return WRC_Abort;
  }

  switch( pExpr->op ){
    /* Consider functions to be constant if all their arguments are constant
    ** and either pWalker->eCode==4 or 5 or the function has the
    ** SQLITE_FUNC_CONST flag. */
    case TK_FUNCTION:
      if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc))
       && !ExprHasProperty(pExpr, EP_WinFunc)
      ){
        if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
        return WRC_Continue;
      }else{
        pWalker->eCode = 0;
        return WRC_Abort;
      }
    case TK_ID:
      /* Convert "true" or "false" in a DEFAULT clause into the
99854
99855
99856
99857
99858
99859
99860
99861
99862
99863
99864
99865
99866
99867
99868
**   (2) the expression does originate in the ON or USING clause
**       of a LEFT JOIN, and
**   (3) the expression does not contain any EP_FixedCol TK_COLUMN
**       operands created by the constant propagation optimization.
**
** When this routine returns true, it indicates that the expression
** can be added to the pParse->pConstExpr list and evaluated once when
** the prepared statement starts up.  See sqlite3ExprCodeAtInit().
*/
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
  return exprIsConst(p, 2, 0);
}

/*
** Walk an expression tree.  Return non-zero if the expression is constant







|







100794
100795
100796
100797
100798
100799
100800
100801
100802
100803
100804
100805
100806
100807
100808
**   (2) the expression does originate in the ON or USING clause
**       of a LEFT JOIN, and
**   (3) the expression does not contain any EP_FixedCol TK_COLUMN
**       operands created by the constant propagation optimization.
**
** When this routine returns true, it indicates that the expression
** can be added to the pParse->pConstExpr list and evaluated once when
** the prepared statement starts up.  See sqlite3ExprCodeRunJustOnce().
*/
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
  return exprIsConst(p, 2, 0);
}

/*
** Walk an expression tree.  Return non-zero if the expression is constant
99930
99931
99932
99933
99934
99935
99936

99937

99938
99939










99940
99941
99942
99943
99944
99945
99946
  w.u.pGroupBy = pGroupBy;
  w.pParse = pParse;
  sqlite3WalkExpr(&w, p);
  return w.eCode;
}

/*

** Walk an expression tree.  Return non-zero if the expression is constant

** or a function call with constant arguments.  Return and 0 if there
** are any variables.










**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
*/
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
  assert( isInit==0 || isInit==1 );







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







100870
100871
100872
100873
100874
100875
100876
100877
100878
100879
100880
100881
100882
100883
100884
100885
100886
100887
100888
100889
100890
100891
100892
100893
100894
100895
100896
100897
100898
  w.u.pGroupBy = pGroupBy;
  w.pParse = pParse;
  sqlite3WalkExpr(&w, p);
  return w.eCode;
}

/*
** Walk an expression tree for the DEFAULT field of a column definition
** in a CREATE TABLE statement.  Return non-zero if the expression is 
** acceptable for use as a DEFAULT.  That is to say, return non-zero if
** the expression is constant or a function call with constant arguments.
** Return and 0 if there are any variables.
**
** isInit is true when parsing from sqlite_master.  isInit is false when
** processing a new CREATE TABLE statement.  When isInit is true, parameters
** (such as ? or $abc) in the expression are converted into NULL.  When
** isInit is false, parameters raise an error.  Parameters should not be
** allowed in a CREATE TABLE statement, but some legacy versions of SQLite
** allowed it, so we need to support it when reading sqlite_master for
** backwards compatibility.
**
** If isInit is true, set EP_FromDDL on every TK_FUNCTION node.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
*/
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
  assert( isInit==0 || isInit==1 );
100029
100030
100031
100032
100033
100034
100035


100036
100037
100038
100039
100040
100041
100042
100043
    case TK_STRING:
    case TK_FLOAT:
    case TK_BLOB:
      return 0;
    case TK_COLUMN:
      return ExprHasProperty(p, EP_CanBeNull) ||
             p->y.pTab==0 ||  /* Reference to column of index on expression */


             (p->iColumn>=0 && p->y.pTab->aCol[p->iColumn].notNull==0);
    default:
      return 1;
  }
}

/*
** Return TRUE if the given expression is a constant which would be







>
>
|







100981
100982
100983
100984
100985
100986
100987
100988
100989
100990
100991
100992
100993
100994
100995
100996
100997
    case TK_STRING:
    case TK_FLOAT:
    case TK_BLOB:
      return 0;
    case TK_COLUMN:
      return ExprHasProperty(p, EP_CanBeNull) ||
             p->y.pTab==0 ||  /* Reference to column of index on expression */
             (p->iColumn>=0
              && ALWAYS(p->y.pTab->aCol!=0) /* Defense against OOM problems */
              && p->y.pTab->aCol[p->iColumn].notNull==0);
    default:
      return 1;
  }
}

/*
** Return TRUE if the given expression is a constant which would be
100506
100507
100508
100509
100510
100511
100512

100513
100514

100515
100516
100517
100518
100519
100520
100521
/*
** Load the Parse object passed as the first argument with an error 
** message of the form:
**
**   "sub-select returns N columns - expected M"
*/   
SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){

  const char *zFmt = "sub-select returns %d columns - expected %d";
  sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);

}
#endif

/*
** Expression pExpr is a vector that has been used in a context where
** it is not permitted. If pExpr is a sub-select vector, this routine 
** loads the Parse object with a message of the form:







>
|
|
>







101460
101461
101462
101463
101464
101465
101466
101467
101468
101469
101470
101471
101472
101473
101474
101475
101476
101477
/*
** Load the Parse object passed as the first argument with an error 
** message of the form:
**
**   "sub-select returns N columns - expected M"
*/   
SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
  if( pParse->nErr==0 ){
    const char *zFmt = "sub-select returns %d columns - expected %d";
    sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
  }
}
#endif

/*
** Expression pExpr is a vector that has been used in a context where
** it is not permitted. If pExpr is a sub-select vector, this routine 
** loads the Parse object with a message of the form:
100601
100602
100603
100604
100605
100606
100607

100608
100609
100610
100611
100612
100613
100614
      sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
      sqlite3VdbeJumpHere(v, addrOnce);
      return;
    }

    /* Begin coding the subroutine */
    ExprSetProperty(pExpr, EP_Subrtn);

    pExpr->y.sub.regReturn = ++pParse->nMem;
    pExpr->y.sub.iAddr =
      sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
    VdbeComment((v, "return address"));

    addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
  }







>







101557
101558
101559
101560
101561
101562
101563
101564
101565
101566
101567
101568
101569
101570
101571
      sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
      sqlite3VdbeJumpHere(v, addrOnce);
      return;
    }

    /* Begin coding the subroutine */
    ExprSetProperty(pExpr, EP_Subrtn);
    assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
    pExpr->y.sub.regReturn = ++pParse->nMem;
    pExpr->y.sub.iAddr =
      sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
    VdbeComment((v, "return address"));

    addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
  }
100682
100683
100684
100685
100686
100687
100688


100689
100690
100691
100692
100693
100694
100695
    int i;
    ExprList *pList = pExpr->x.pList;
    struct ExprList_item *pItem;
    int r1, r2;
    affinity = sqlite3ExprAffinity(pLeft);
    if( affinity<=SQLITE_AFF_NONE ){
      affinity = SQLITE_AFF_BLOB;


    }
    if( pKeyInfo ){
      assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
      pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
    }

    /* Loop through each expression in <exprlist>. */







>
>







101639
101640
101641
101642
101643
101644
101645
101646
101647
101648
101649
101650
101651
101652
101653
101654
    int i;
    ExprList *pList = pExpr->x.pList;
    struct ExprList_item *pItem;
    int r1, r2;
    affinity = sqlite3ExprAffinity(pLeft);
    if( affinity<=SQLITE_AFF_NONE ){
      affinity = SQLITE_AFF_BLOB;
    }else if( affinity==SQLITE_AFF_REAL ){
      affinity = SQLITE_AFF_NUMERIC;
    }
    if( pKeyInfo ){
      assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
      pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
    }

    /* Loop through each expression in <exprlist>. */
100920
100921
100922
100923
100924
100925
100926

100927

100928
100929
100930
100931
100932
100933
100934
  int i;                /* loop counter */
  int destStep2;        /* Where to jump when NULLs seen in step 2 */
  int destStep6 = 0;    /* Start of code for Step 6 */
  int addrTruthOp;      /* Address of opcode that determines the IN is true */
  int destNotNull;      /* Jump here if a comparison is not true in step 6 */
  int addrTop;          /* Top of the step-6 loop */ 
  int iTab = 0;         /* Index to use */



  pLeft = pExpr->pLeft;
  if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
  zAff = exprINAffinity(pParse, pExpr);
  nVector = sqlite3ExprVectorSize(pExpr->pLeft);
  aiMap = (int*)sqlite3DbMallocZero(
      pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
  );







>

>







101879
101880
101881
101882
101883
101884
101885
101886
101887
101888
101889
101890
101891
101892
101893
101894
101895
  int i;                /* loop counter */
  int destStep2;        /* Where to jump when NULLs seen in step 2 */
  int destStep6 = 0;    /* Start of code for Step 6 */
  int addrTruthOp;      /* Address of opcode that determines the IN is true */
  int destNotNull;      /* Jump here if a comparison is not true in step 6 */
  int addrTop;          /* Top of the step-6 loop */ 
  int iTab = 0;         /* Index to use */
  u8 okConstFactor = pParse->okConstFactor;

  assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
  pLeft = pExpr->pLeft;
  if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
  zAff = exprINAffinity(pParse, pExpr);
  nVector = sqlite3ExprVectorSize(pExpr->pLeft);
  aiMap = (int*)sqlite3DbMallocZero(
      pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
  );
100963
100964
100965
100966
100967
100968
100969
100970





100971

100972
100973
100974
100975
100976
100977
100978
  ** vector, then it is stored in an array of nVector registers starting 
  ** at r1.
  **
  ** sqlite3FindInIndex() might have reordered the fields of the LHS vector
  ** so that the fields are in the same order as an existing index.   The
  ** aiMap[] array contains a mapping from the original LHS field order to
  ** the field order that matches the RHS index.
  */





  rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy);

  for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */
  if( i==nVector ){
    /* LHS fields are not reordered */
    rLhs = rLhsOrig;
  }else{
    /* Need to reorder the LHS fields according to aiMap */
    rLhs = sqlite3GetTempRange(pParse, nVector);







|
>
>
>
>
>

>







101924
101925
101926
101927
101928
101929
101930
101931
101932
101933
101934
101935
101936
101937
101938
101939
101940
101941
101942
101943
101944
101945
  ** vector, then it is stored in an array of nVector registers starting 
  ** at r1.
  **
  ** sqlite3FindInIndex() might have reordered the fields of the LHS vector
  ** so that the fields are in the same order as an existing index.   The
  ** aiMap[] array contains a mapping from the original LHS field order to
  ** the field order that matches the RHS index.
  **
  ** Avoid factoring the LHS of the IN(...) expression out of the loop,
  ** even if it is constant, as OP_Affinity may be used on the register
  ** by code generated below.  */
  assert( pParse->okConstFactor==okConstFactor );
  pParse->okConstFactor = 0;
  rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy);
  pParse->okConstFactor = okConstFactor;
  for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */
  if( i==nVector ){
    /* LHS fields are not reordered */
    rLhs = rLhsOrig;
  }else{
    /* Need to reorder the LHS fields according to aiMap */
    rLhs = sqlite3GetTempRange(pParse, nVector);
100990
100991
100992
100993
100994
100995
100996
100997
100998
100999
101000
101001
101002
101003
101004
101005
101006
101007
101008
101009
101010
101011
101012
101013
101014

101015

101016
101017
101018
101019


101020
101021

101022
101023
101024


101025
101026
101027
101028
101029
101030
101031
101032
101033
101034
101035
101036
101037
101038
101039
101040
101041
101042
101043
101044
101045
101046

101047
101048
101049
101050
101051
101052
101053
  if( eType==IN_INDEX_NOOP ){
    ExprList *pList = pExpr->x.pList;
    CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
    int labelOk = sqlite3VdbeMakeLabel(pParse);
    int r2, regToFree;
    int regCkNull = 0;
    int ii;
    int bLhsReal;  /* True if the LHS of the IN has REAL affinity */
    assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    if( destIfNull!=destIfFalse ){
      regCkNull = sqlite3GetTempReg(pParse);
      sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
    }
    bLhsReal = sqlite3ExprAffinity(pExpr->pLeft)==SQLITE_AFF_REAL;
    for(ii=0; ii<pList->nExpr; ii++){
      if( bLhsReal ){
        r2 = regToFree = sqlite3GetTempReg(pParse);
        sqlite3ExprCode(pParse, pList->a[ii].pExpr, r2);
        sqlite3VdbeAddOp4(v, OP_Affinity, r2, 1, 0, "E", P4_STATIC);
      }else{
        r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, &regToFree);
      }
      if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
        sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
      }

      if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){

        sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2,
                          (void*)pColl, P4_COLLSEQ);
        VdbeCoverageIf(v, ii<pList->nExpr-1);
        VdbeCoverageIf(v, ii==pList->nExpr-1);


        sqlite3VdbeChangeP5(v, zAff[0]);
      }else{

        assert( destIfNull==destIfFalse );
        sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2,
                          (void*)pColl, P4_COLLSEQ); VdbeCoverage(v);


        sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL);
      }
      sqlite3ReleaseTempReg(pParse, regToFree);
    }
    if( regCkNull ){
      sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
      sqlite3VdbeGoto(v, destIfFalse);
    }
    sqlite3VdbeResolveLabel(v, labelOk);
    sqlite3ReleaseTempReg(pParse, regCkNull);
    goto sqlite3ExprCodeIN_finished;
  }

  /* Step 2: Check to see if the LHS contains any NULL columns.  If the
  ** LHS does contain NULLs then the result must be either FALSE or NULL.
  ** We will then skip the binary search of the RHS.
  */
  if( destIfNull==destIfFalse ){
    destStep2 = destIfFalse;
  }else{
    destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse);
  }

  for(i=0; i<nVector; i++){
    Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
    if( sqlite3ExprCanBeNull(p) ){
      sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2);
      VdbeCoverage(v);
    }
  }







<





<

<
<
<
<
<
|
<



>

>
|

|
|
>
>


>

|
|
>
>


<



















>







101957
101958
101959
101960
101961
101962
101963

101964
101965
101966
101967
101968

101969





101970

101971
101972
101973
101974
101975
101976
101977
101978
101979
101980
101981
101982
101983
101984
101985
101986
101987
101988
101989
101990
101991
101992

101993
101994
101995
101996
101997
101998
101999
102000
102001
102002
102003
102004
102005
102006
102007
102008
102009
102010
102011
102012
102013
102014
102015
102016
102017
102018
102019
  if( eType==IN_INDEX_NOOP ){
    ExprList *pList = pExpr->x.pList;
    CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
    int labelOk = sqlite3VdbeMakeLabel(pParse);
    int r2, regToFree;
    int regCkNull = 0;
    int ii;

    assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    if( destIfNull!=destIfFalse ){
      regCkNull = sqlite3GetTempReg(pParse);
      sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
    }

    for(ii=0; ii<pList->nExpr; ii++){





      r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, &regToFree);

      if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
        sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
      }
      sqlite3ReleaseTempReg(pParse, regToFree);
      if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){
        int op = rLhs!=r2 ? OP_Eq : OP_NotNull;
        sqlite3VdbeAddOp4(v, op, rLhs, labelOk, r2,
                          (void*)pColl, P4_COLLSEQ);
        VdbeCoverageIf(v, ii<pList->nExpr-1 && op==OP_Eq);
        VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_Eq);
        VdbeCoverageIf(v, ii<pList->nExpr-1 && op==OP_NotNull);
        VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_NotNull);
        sqlite3VdbeChangeP5(v, zAff[0]);
      }else{
        int op = rLhs!=r2 ? OP_Ne : OP_IsNull;
        assert( destIfNull==destIfFalse );
        sqlite3VdbeAddOp4(v, op, rLhs, destIfFalse, r2,
                          (void*)pColl, P4_COLLSEQ);
        VdbeCoverageIf(v, op==OP_Ne);
        VdbeCoverageIf(v, op==OP_IsNull);
        sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL);
      }

    }
    if( regCkNull ){
      sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
      sqlite3VdbeGoto(v, destIfFalse);
    }
    sqlite3VdbeResolveLabel(v, labelOk);
    sqlite3ReleaseTempReg(pParse, regCkNull);
    goto sqlite3ExprCodeIN_finished;
  }

  /* Step 2: Check to see if the LHS contains any NULL columns.  If the
  ** LHS does contain NULLs then the result must be either FALSE or NULL.
  ** We will then skip the binary search of the RHS.
  */
  if( destIfNull==destIfFalse ){
    destStep2 = destIfFalse;
  }else{
    destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse);
  }
  if( pParse->nErr ) goto sqlite3ExprCodeIN_finished;
  for(i=0; i<nVector; i++){
    Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
    if( sqlite3ExprCanBeNull(p) ){
      sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2);
      VdbeCoverage(v);
    }
  }
101231
101232
101233
101234
101235
101236
101237









101238
101239
101240
101241
101242

101243
101244
101245
101246
101247
101248
101249
** and store the result in register regOut
*/
SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
  Parse *pParse,
  Column *pCol,
  int regOut
){









  sqlite3ExprCode(pParse, pCol->pDflt, regOut);
  if( pCol->affinity>=SQLITE_AFF_TEXT ){
    sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, regOut, 1, 0,
                      &pCol->affinity, 1);
  }

}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */

/*
** Generate code to extract the value of the iCol-th column of a table.
*/
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(







>
>
>
>
>
>
>
>
>
|

<
|

>







102197
102198
102199
102200
102201
102202
102203
102204
102205
102206
102207
102208
102209
102210
102211
102212
102213
102214

102215
102216
102217
102218
102219
102220
102221
102222
102223
102224
** and store the result in register regOut
*/
SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
  Parse *pParse,
  Column *pCol,
  int regOut
){
  int iAddr;
  Vdbe *v = pParse->pVdbe;
  assert( v!=0 );
  assert( pParse->iSelfTab!=0 );
  if( pParse->iSelfTab>0 ){
    iAddr = sqlite3VdbeAddOp3(v, OP_IfNullRow, pParse->iSelfTab-1, 0, regOut);
  }else{
    iAddr = 0;
  }
  sqlite3ExprCodeCopy(pParse, pCol->pDflt, regOut);
  if( pCol->affinity>=SQLITE_AFF_TEXT ){

    sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1);
  }
  if( iAddr ) sqlite3VdbeJumpHere(v, iAddr);
}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */

/*
** Generate code to extract the value of the iCol-th column of a table.
*/
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
101310
101311
101312
101313
101314
101315
101316
101317

101318
101319
101320
101321
101322
101323
101324
101325
101326
101327
101328
101329
101330
101331
101332
101333
101334
  int iTable,      /* The cursor pointing to the table */
  int iReg,        /* Store results here */
  u8 p5            /* P5 value for OP_Column + FLAGS */
){
  assert( pParse->pVdbe!=0 );
  sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
  if( p5 ){
    sqlite3VdbeChangeP5(pParse->pVdbe, p5);

  }
  return iReg;
}

/*
** Generate code to move content from registers iFrom...iFrom+nReg-1
** over to iTo..iTo+nReg-1.
*/
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
  assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
  sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
}

/*
** Convert a scalar expression node to a TK_REGISTER referencing
** register iReg.  The caller must ensure that iReg already contains
** the correct value for the expression.







|
>









<







102285
102286
102287
102288
102289
102290
102291
102292
102293
102294
102295
102296
102297
102298
102299
102300
102301
102302

102303
102304
102305
102306
102307
102308
102309
  int iTable,      /* The cursor pointing to the table */
  int iReg,        /* Store results here */
  u8 p5            /* P5 value for OP_Column + FLAGS */
){
  assert( pParse->pVdbe!=0 );
  sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
  if( p5 ){
    VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1);
    if( pOp->opcode==OP_Column ) pOp->p5 = p5;
  }
  return iReg;
}

/*
** Generate code to move content from registers iFrom...iFrom+nReg-1
** over to iTo..iTo+nReg-1.
*/
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){

  sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
}

/*
** Convert a scalar expression node to a TK_REGISTER referencing
** register iReg.  The caller must ensure that iReg already contains
** the correct value for the expression.
101372
101373
101374
101375
101376
101377
101378















































































































101379
101380
101381
101382
101383
101384
101385
        sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult);
      }
    }
  }
  return iResult;
}

















































































































/*
** Generate code into the current Vdbe to evaluate the given
** expression.  Attempt to store the results in register "target".
** Return the register where results are stored.
**
** With this routine, there is no guarantee that results will







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







102347
102348
102349
102350
102351
102352
102353
102354
102355
102356
102357
102358
102359
102360
102361
102362
102363
102364
102365
102366
102367
102368
102369
102370
102371
102372
102373
102374
102375
102376
102377
102378
102379
102380
102381
102382
102383
102384
102385
102386
102387
102388
102389
102390
102391
102392
102393
102394
102395
102396
102397
102398
102399
102400
102401
102402
102403
102404
102405
102406
102407
102408
102409
102410
102411
102412
102413
102414
102415
102416
102417
102418
102419
102420
102421
102422
102423
102424
102425
102426
102427
102428
102429
102430
102431
102432
102433
102434
102435
102436
102437
102438
102439
102440
102441
102442
102443
102444
102445
102446
102447
102448
102449
102450
102451
102452
102453
102454
102455
102456
102457
102458
102459
102460
102461
102462
102463
102464
102465
102466
102467
102468
102469
102470
102471
        sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult);
      }
    }
  }
  return iResult;
}

/*
** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5)
** so that a subsequent copy will not be merged into this one.
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
  if( sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){
    sqlite3VdbeChangeP5(v, 1);  /* Tag trailing OP_Copy as not mergable */
  }
}

/*
** Generate code to implement special SQL functions that are implemented
** in-line rather than by using the usual callbacks.
*/
static int exprCodeInlineFunction(
  Parse *pParse,        /* Parsing context */
  ExprList *pFarg,      /* List of function arguments */
  int iFuncId,          /* Function ID.  One of the INTFUNC_... values */
  int target            /* Store function result in this register */
){
  int nFarg;
  Vdbe *v = pParse->pVdbe;
  assert( v!=0 );
  assert( pFarg!=0 );
  nFarg = pFarg->nExpr;
  assert( nFarg>0 );  /* All in-line functions have at least one argument */
  switch( iFuncId ){
    case INLINEFUNC_coalesce: {
      /* Attempt a direct implementation of the built-in COALESCE() and
      ** IFNULL() functions.  This avoids unnecessary evaluation of
      ** arguments past the first non-NULL argument.
      */
      int endCoalesce = sqlite3VdbeMakeLabel(pParse);
      int i;
      assert( nFarg>=2 );
      sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
      for(i=1; i<nFarg; i++){
        sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
        VdbeCoverage(v);
        sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
      }
      setDoNotMergeFlagOnCopy(v);
      sqlite3VdbeResolveLabel(v, endCoalesce);
      break;
    }

    default: {   
      /* The UNLIKELY() function is a no-op.  The result is the value
      ** of the first argument.
      */
      assert( nFarg==1 || nFarg==2 );
      target = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
      break;
    }

  /***********************************************************************
  ** Test-only SQL functions that are only usable if enabled
  ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS
  */
    case INLINEFUNC_expr_compare: {
      /* Compare two expressions using sqlite3ExprCompare() */
      assert( nFarg==2 );
      sqlite3VdbeAddOp2(v, OP_Integer, 
         sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
         target);
      break;
    }

    case INLINEFUNC_expr_implies_expr: {
      /* Compare two expressions using sqlite3ExprImpliesExpr() */
      assert( nFarg==2 );
      sqlite3VdbeAddOp2(v, OP_Integer, 
         sqlite3ExprImpliesExpr(pParse,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
         target);
      break;
    }

    case INLINEFUNC_implies_nonnull_row: {
      /* REsult of sqlite3ExprImpliesNonNullRow() */
      Expr *pA1;
      assert( nFarg==2 );
      pA1 = pFarg->a[1].pExpr;
      if( pA1->op==TK_COLUMN ){
        sqlite3VdbeAddOp2(v, OP_Integer, 
           sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
           target);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, target);
      }
      break;
    }

#ifdef SQLITE_DEBUG
    case INLINEFUNC_affinity: {
      /* The AFFINITY() function evaluates to a string that describes
      ** the type affinity of the argument.  This is used for testing of
      ** the SQLite type logic.
      */
      const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
      char aff;
      assert( nFarg==1 );
      aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
      sqlite3VdbeLoadString(v, target, 
              (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
      break;
    }
#endif
  }
  return target;
}


/*
** Generate code into the current Vdbe to evaluate the given
** expression.  Attempt to store the results in register "target".
** Return the register where results are stored.
**
** With this routine, there is no guarantee that results will
101404
101405
101406
101407
101408
101409
101410

101411
101412
101413
101414
101415
101416
101417
101418
101419
101420

101421
101422








101423
101424
101425
101426
101427
101428

101429
101430
101431
101432
101433
101434
101435

101436

101437



101438
101439
101440
101441
101442
101443
101444
101445
101446
101447
101448
101449
101450
101451
101452
101453
101454
101455
101456
101457
101458
101459
101460
101461
101462
101463
101464
101465
101466
101467
101468
101469
101470
101471
101472
    return 0;
  }

expr_code_doover:
  if( pExpr==0 ){
    op = TK_NULL;
  }else{

    op = pExpr->op;
  }
  switch( op ){
    case TK_AGG_COLUMN: {
      AggInfo *pAggInfo = pExpr->pAggInfo;
      struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
      if( !pAggInfo->directMode ){
        assert( pCol->iMem>0 );
        return pCol->iMem;
      }else if( pAggInfo->useSortingIdx ){

        sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
                              pCol->iSorterColumn, target);








        return target;
      }
      /* Otherwise, fall thru into the TK_COLUMN case */
    }
    case TK_COLUMN: {
      int iTab = pExpr->iTable;

      if( ExprHasProperty(pExpr, EP_FixedCol) ){
        /* This COLUMN expression is really a constant due to WHERE clause
        ** constraints, and that constant is coded by the pExpr->pLeft
        ** expresssion.  However, make sure the constant has the correct
        ** datatype by applying the Affinity of the table column to the
        ** constant.
        */

        int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);

        int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);



        if( aff>SQLITE_AFF_BLOB ){
          static const char zAff[] = "B\000C\000D\000E";
          assert( SQLITE_AFF_BLOB=='A' );
          assert( SQLITE_AFF_TEXT=='B' );
          if( iReg!=target ){
            sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target);
            iReg = target;
          }
          sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
                            &zAff[(aff-'B')*2], P4_STATIC);
        }
        return iReg;
      }
      if( iTab<0 ){
        if( pParse->iSelfTab<0 ){
          /* Other columns in the same row for CHECK constraints or
          ** generated columns or for inserting into partial index.
          ** The row is unpacked into registers beginning at
          ** 0-(pParse->iSelfTab).  The rowid (if any) is in a register
          ** immediately prior to the first column.
          */
          Column *pCol;
          Table *pTab = pExpr->y.pTab;
          int iSrc;
          int iCol = pExpr->iColumn;
          assert( pTab!=0 );
          assert( iCol>=XN_ROWID );
          assert( iCol<pExpr->y.pTab->nCol );
          if( iCol<0 ){
            return -1-pParse->iSelfTab;
          }
          pCol = pTab->aCol + iCol;
          testcase( iCol!=sqlite3TableColumnToStorage(pTab,iCol) );
          iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS







>










>


>
>
>
>
>
>
>
>






>







>
|
>
|
>
>
>




<
<
<
<



















|







102490
102491
102492
102493
102494
102495
102496
102497
102498
102499
102500
102501
102502
102503
102504
102505
102506
102507
102508
102509
102510
102511
102512
102513
102514
102515
102516
102517
102518
102519
102520
102521
102522
102523
102524
102525
102526
102527
102528
102529
102530
102531
102532
102533
102534
102535
102536
102537
102538
102539
102540
102541
102542
102543




102544
102545
102546
102547
102548
102549
102550
102551
102552
102553
102554
102555
102556
102557
102558
102559
102560
102561
102562
102563
102564
102565
102566
102567
102568
102569
102570
    return 0;
  }

expr_code_doover:
  if( pExpr==0 ){
    op = TK_NULL;
  }else{
    assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
    op = pExpr->op;
  }
  switch( op ){
    case TK_AGG_COLUMN: {
      AggInfo *pAggInfo = pExpr->pAggInfo;
      struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
      if( !pAggInfo->directMode ){
        assert( pCol->iMem>0 );
        return pCol->iMem;
      }else if( pAggInfo->useSortingIdx ){
        Table *pTab = pCol->pTab;
        sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
                              pCol->iSorterColumn, target);
        if( pCol->iColumn<0 ){
          VdbeComment((v,"%s.rowid",pTab->zName));
        }else{
          VdbeComment((v,"%s.%s",pTab->zName,pTab->aCol[pCol->iColumn].zName));
          if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){
            sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
          }
        }
        return target;
      }
      /* Otherwise, fall thru into the TK_COLUMN case */
    }
    case TK_COLUMN: {
      int iTab = pExpr->iTable;
      int iReg;
      if( ExprHasProperty(pExpr, EP_FixedCol) ){
        /* This COLUMN expression is really a constant due to WHERE clause
        ** constraints, and that constant is coded by the pExpr->pLeft
        ** expresssion.  However, make sure the constant has the correct
        ** datatype by applying the Affinity of the table column to the
        ** constant.
        */
        int aff;
        iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
        if( pExpr->y.pTab ){
          aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
        }else{
          aff = pExpr->affExpr;
        }
        if( aff>SQLITE_AFF_BLOB ){
          static const char zAff[] = "B\000C\000D\000E";
          assert( SQLITE_AFF_BLOB=='A' );
          assert( SQLITE_AFF_TEXT=='B' );




          sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
                            &zAff[(aff-'B')*2], P4_STATIC);
        }
        return iReg;
      }
      if( iTab<0 ){
        if( pParse->iSelfTab<0 ){
          /* Other columns in the same row for CHECK constraints or
          ** generated columns or for inserting into partial index.
          ** The row is unpacked into registers beginning at
          ** 0-(pParse->iSelfTab).  The rowid (if any) is in a register
          ** immediately prior to the first column.
          */
          Column *pCol;
          Table *pTab = pExpr->y.pTab;
          int iSrc;
          int iCol = pExpr->iColumn;
          assert( pTab!=0 );
          assert( iCol>=XN_ROWID );
          assert( iCol<pTab->nCol );
          if( iCol<0 ){
            return -1-pParse->iSelfTab;
          }
          pCol = pTab->aCol + iCol;
          testcase( iCol!=sqlite3TableColumnToStorage(pTab,iCol) );
          iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
101493
101494
101495
101496
101497
101498
101499
101500
101501
101502




101503
101504
101505
101506
101507
101508
101509
          }
        }else{
          /* Coding an expression that is part of an index where column names
          ** in the index refer to the table to which the index belongs */
          iTab = pParse->iSelfTab - 1;
        }
      }
      return sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
                               pExpr->iColumn, iTab, target,
                               pExpr->op2);




    }
    case TK_INTEGER: {
      codeInteger(pParse, pExpr, 0, target);
      return target;
    }
    case TK_TRUEFALSE: {
      sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprTruthValue(pExpr), target);







|


>
>
>
>







102591
102592
102593
102594
102595
102596
102597
102598
102599
102600
102601
102602
102603
102604
102605
102606
102607
102608
102609
102610
102611
          }
        }else{
          /* Coding an expression that is part of an index where column names
          ** in the index refer to the table to which the index belongs */
          iTab = pParse->iSelfTab - 1;
        }
      }
      iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
                               pExpr->iColumn, iTab, target,
                               pExpr->op2);
      if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){
        sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
      }
      return iReg;
    }
    case TK_INTEGER: {
      codeInteger(pParse, pExpr, 0, target);
      return target;
    }
    case TK_TRUEFALSE: {
      sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprTruthValue(pExpr), target);
101517
101518
101519
101520
101521
101522
101523





101524
101525
101526
101527
101528
101529
101530
101531
    }
#endif
    case TK_STRING: {
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
      return target;
    }





    case TK_NULL: {
      sqlite3VdbeAddOp2(v, OP_Null, 0, target);
      return target;
    }
#ifndef SQLITE_OMIT_BLOB_LITERAL
    case TK_BLOB: {
      int n;
      const char *z;







>
>
>
>
>
|







102619
102620
102621
102622
102623
102624
102625
102626
102627
102628
102629
102630
102631
102632
102633
102634
102635
102636
102637
102638
    }
#endif
    case TK_STRING: {
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
      return target;
    }
    default: {
      /* Make NULL the default case so that if a bug causes an illegal
      ** Expr node to be passed into this function, it will be handled
      ** sanely and not crash.  But keep the assert() to bring the problem
      ** to the attention of the developers. */
      assert( op==TK_NULL );
      sqlite3VdbeAddOp2(v, OP_Null, 0, target);
      return target;
    }
#ifndef SQLITE_OMIT_BLOB_LITERAL
    case TK_BLOB: {
      int n;
      const char *z;
101544
101545
101546
101547
101548
101549
101550
101551
101552
101553
101554
101555
101556
101557
101558
    case TK_VARIABLE: {
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      assert( pExpr->u.zToken!=0 );
      assert( pExpr->u.zToken[0]!=0 );
      sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
      if( pExpr->u.zToken[1]!=0 ){
        const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
        assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 );
        pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
        sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
      }
      return target;
    }
    case TK_REGISTER: {
      return pExpr->iTable;







|







102651
102652
102653
102654
102655
102656
102657
102658
102659
102660
102661
102662
102663
102664
102665
    case TK_VARIABLE: {
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      assert( pExpr->u.zToken!=0 );
      assert( pExpr->u.zToken[0]!=0 );
      sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
      if( pExpr->u.zToken[1]!=0 ){
        const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
        assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) );
        pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
        sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
      }
      return target;
    }
    case TK_REGISTER: {
      return pExpr->iTable;
101643
101644
101645
101646
101647
101648
101649

101650
101651
101652
101653
101654
101655
101656
        codeReal(v, pLeft->u.zToken, 1, target);
        return target;
#endif
      }else{
        tempX.op = TK_INTEGER;
        tempX.flags = EP_IntValue|EP_TokenOnly;
        tempX.u.iValue = 0;

        r1 = sqlite3ExprCodeTemp(pParse, &tempX, &regFree1);
        r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree2);
        sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
        testcase( regFree2==0 );
      }
      break;
    }







>







102750
102751
102752
102753
102754
102755
102756
102757
102758
102759
102760
102761
102762
102763
102764
        codeReal(v, pLeft->u.zToken, 1, target);
        return target;
#endif
      }else{
        tempX.op = TK_INTEGER;
        tempX.flags = EP_IntValue|EP_TokenOnly;
        tempX.u.iValue = 0;
        ExprClearVVAProperties(&tempX);
        r1 = sqlite3ExprCodeTemp(pParse, &tempX, &regFree1);
        r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree2);
        sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
        testcase( regFree2==0 );
      }
      break;
    }
101714
101715
101716
101717
101718
101719
101720
101721
101722
101723
101724
101725
101726
101727
101728
101729
101730
101731
101732
101733
101734
101735
101736
101737
101738
101739
101740
101741
101742
101743
101744
101745
101746
101747
101748
101749
101750
101751
101752
101753
101754
101755
101756
101757
101758
101759
101760
101761
101762
101763
101764
101765
101766
101767
101768
101769
101770
101771
101772
101773
101774
101775
101776
101777
101778
101779
101780
101781
101782
101783
101784
101785
101786
101787
101788
101789
101790
101791
#ifndef SQLITE_OMIT_WINDOWFUNC
      if( ExprHasProperty(pExpr, EP_WinFunc) ){
        return pExpr->y.pWin->regResult;
      }
#endif

      if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
        /* SQL functions can be expensive. So try to move constant functions
        ** out of the inner loop, even if that means an extra OP_Copy. */
        return sqlite3ExprCodeAtInit(pParse, pExpr, -1);
      }
      assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
      if( ExprHasProperty(pExpr, EP_TokenOnly) ){
        pFarg = 0;
      }else{
        pFarg = pExpr->x.pList;
      }
      nFarg = pFarg ? pFarg->nExpr : 0;
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      zId = pExpr->u.zToken;
      pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
      if( pDef==0 && pParse->explain ){
        pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0);
      }
#endif
      if( pDef==0 || pDef->xFinalize!=0 ){
        sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
        break;
      }

      /* Attempt a direct implementation of the built-in COALESCE() and
      ** IFNULL() functions.  This avoids unnecessary evaluation of
      ** arguments past the first non-NULL argument.
      */
      if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){
        int endCoalesce = sqlite3VdbeMakeLabel(pParse);
        assert( nFarg>=2 );
        sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
        for(i=1; i<nFarg; i++){
          sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
          VdbeCoverage(v);
          sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
        }
        sqlite3VdbeResolveLabel(v, endCoalesce);
        break;
      }

      /* The UNLIKELY() function is a no-op.  The result is the value
      ** of the first argument.
      */
      if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
        assert( nFarg>=1 );
        return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
      }

#ifdef SQLITE_DEBUG
      /* The AFFINITY() function evaluates to a string that describes
      ** the type affinity of the argument.  This is used for testing of
      ** the SQLite type logic.
      */
      if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){
        const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
        char aff;
        assert( nFarg==1 );
        aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
        sqlite3VdbeLoadString(v, target, 
                (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
        return target;
      }
#endif

      for(i=0; i<nFarg; i++){
        if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
          testcase( i==31 );
          constMask |= MASKBIT32(i);
        }
        if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){







|
|
|


|
<
<
|
<













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

<







102822
102823
102824
102825
102826
102827
102828
102829
102830
102831
102832
102833
102834


102835

102836
102837
102838
102839
102840
102841
102842
102843
102844
102845
102846
102847
102848





102849











102850



102851

102852

102853





102854



102855



102856

102857
102858
102859
102860
102861
102862
102863
#ifndef SQLITE_OMIT_WINDOWFUNC
      if( ExprHasProperty(pExpr, EP_WinFunc) ){
        return pExpr->y.pWin->regResult;
      }
#endif

      if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
        /* SQL functions can be expensive. So try to avoid running them
        ** multiple times if we know they always give the same result */
        return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
      }
      assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
      assert( !ExprHasProperty(pExpr, EP_TokenOnly) );


      pFarg = pExpr->x.pList;

      nFarg = pFarg ? pFarg->nExpr : 0;
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      zId = pExpr->u.zToken;
      pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
      if( pDef==0 && pParse->explain ){
        pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0);
      }
#endif
      if( pDef==0 || pDef->xFinalize!=0 ){
        sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
        break;
      }





      if( pDef->funcFlags & SQLITE_FUNC_INLINE ){











        assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 );



        assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 );

        return exprCodeInlineFunction(pParse, pFarg,

             SQLITE_PTR_TO_INT(pDef->pUserData), target);





      }else if( pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE) ){



        sqlite3ExprFunctionUsable(pParse, pExpr, pDef);



      }


      for(i=0; i<nFarg; i++){
        if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
          testcase( i==31 );
          constMask |= MASKBIT32(i);
        }
        if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
101857
101858
101859
101860
101861
101862
101863
101864

101865



101866
101867
101868
101869
101870
101871
101872
        }
      }else
#endif
      {
        sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
                                   pDef, pExpr->op2);
      }
      if( nFarg && constMask==0 ){

        sqlite3ReleaseTempRange(pParse, r1, nFarg);



      }
      return target;
    }
#ifndef SQLITE_OMIT_SUBQUERY
    case TK_EXISTS:
    case TK_SELECT: {
      int nCol;







|
>
|
>
>
>







102929
102930
102931
102932
102933
102934
102935
102936
102937
102938
102939
102940
102941
102942
102943
102944
102945
102946
102947
102948
        }
      }else
#endif
      {
        sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
                                   pDef, pExpr->op2);
      }
      if( nFarg ){
        if( constMask==0 ){
          sqlite3ReleaseTempRange(pParse, r1, nFarg);
        }else{
          sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask, 1);
        }
      }
      return target;
    }
#ifndef SQLITE_OMIT_SUBQUERY
    case TK_EXISTS:
    case TK_SELECT: {
      int nCol;
101954
101955
101956
101957
101958
101959
101960
101961
101962
101963
101964
101965
101966
101967
101968
      **   p1==0   ->    old.rowid     p1==3   ->    new.rowid
      **   p1==1   ->    old.a         p1==4   ->    new.a
      **   p1==2   ->    old.b         p1==5   ->    new.b       
      */
      Table *pTab = pExpr->y.pTab;
      int iCol = pExpr->iColumn;
      int p1 = pExpr->iTable * (pTab->nCol+1) + 1 
                     + (iCol>=0 ? sqlite3TableColumnToStorage(pTab, iCol) : -1);

      assert( pExpr->iTable==0 || pExpr->iTable==1 );
      assert( iCol>=-1 && iCol<pTab->nCol );
      assert( pTab->iPKey<0 || iCol!=pTab->iPKey );
      assert( p1>=0 && p1<(pTab->nCol*2+2) );

      sqlite3VdbeAddOp2(v, OP_Param, p1, target);







|







103030
103031
103032
103033
103034
103035
103036
103037
103038
103039
103040
103041
103042
103043
103044
      **   p1==0   ->    old.rowid     p1==3   ->    new.rowid
      **   p1==1   ->    old.a         p1==4   ->    new.a
      **   p1==2   ->    old.b         p1==5   ->    new.b       
      */
      Table *pTab = pExpr->y.pTab;
      int iCol = pExpr->iColumn;
      int p1 = pExpr->iTable * (pTab->nCol+1) + 1 
                     + sqlite3TableColumnToStorage(pTab, iCol);

      assert( pExpr->iTable==0 || pExpr->iTable==1 );
      assert( iCol>=-1 && iCol<pTab->nCol );
      assert( pTab->iPKey<0 || iCol!=pTab->iPKey );
      assert( p1>=0 && p1<(pTab->nCol*2+2) );

      sqlite3VdbeAddOp2(v, OP_Param, p1, target);
102028
102029
102030
102031
102032
102033
102034
102035
102036
102037
102038
102039
102040
102041
102042
    ** is even, then Y is omitted and the "otherwise" result is NULL.
    ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1].
    **
    ** The result of the expression is the Ri for the first matching Ei,
    ** or if there is no matching Ei, the ELSE term Y, or if there is
    ** no ELSE term, NULL.
    */
    default: assert( op==TK_CASE ); {
      int endLabel;                     /* GOTO label for end of CASE stmt */
      int nextCase;                     /* GOTO label for next WHEN clause */
      int nExpr;                        /* 2x number of WHEN terms */
      int i;                            /* Loop counter */
      ExprList *pEList;                 /* List of WHEN terms */
      struct ExprList_item *aListelem;  /* Array of WHEN terms */
      Expr opCompare;                   /* The X==Ei expression */







|







103104
103105
103106
103107
103108
103109
103110
103111
103112
103113
103114
103115
103116
103117
103118
    ** is even, then Y is omitted and the "otherwise" result is NULL.
    ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1].
    **
    ** The result of the expression is the Ri for the first matching Ei,
    ** or if there is no matching Ei, the ELSE term Y, or if there is
    ** no ELSE term, NULL.
    */
    case TK_CASE: {
      int endLabel;                     /* GOTO label for end of CASE stmt */
      int nextCase;                     /* GOTO label for next WHEN clause */
      int nExpr;                        /* 2x number of WHEN terms */
      int i;                            /* Loop counter */
      ExprList *pEList;                 /* List of WHEN terms */
      struct ExprList_item *aListelem;  /* Array of WHEN terms */
      Expr opCompare;                   /* The X==Ei expression */
102087
102088
102089
102090
102091
102092
102093

102094
102095
102096
102097
102098
102099
102100
      }
      if( (nExpr&1)!=0 ){
        sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, target);
      }
      sqlite3ExprDelete(db, pDel);

      sqlite3VdbeResolveLabel(v, endLabel);
      break;
    }
#ifndef SQLITE_OMIT_TRIGGER
    case TK_RAISE: {
      assert( pExpr->affExpr==OE_Rollback 
           || pExpr->affExpr==OE_Abort







>







103163
103164
103165
103166
103167
103168
103169
103170
103171
103172
103173
103174
103175
103176
103177
      }
      if( (nExpr&1)!=0 ){
        sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, target);
      }
      sqlite3ExprDelete(db, pDel);
      setDoNotMergeFlagOnCopy(v);
      sqlite3VdbeResolveLabel(v, endLabel);
      break;
    }
#ifndef SQLITE_OMIT_TRIGGER
    case TK_RAISE: {
      assert( pExpr->affExpr==OE_Rollback 
           || pExpr->affExpr==OE_Abort
102125
102126
102127
102128
102129
102130
102131
102132






102133
102134
102135
102136
102137
102138


102139
102140
102141
102142
102143
102144
102145
102146
102147
102148
102149
102150
102151
102152
102153
102154
102155
102156
102157














102158
102159
102160
102161
102162
102163
102164
102165

102166
102167
102168
102169
102170
102171
102172
  }
  sqlite3ReleaseTempReg(pParse, regFree1);
  sqlite3ReleaseTempReg(pParse, regFree2);
  return inReg;
}

/*
** Factor out the code of the given expression to initialization time.






**
** If regDest>=0 then the result is always stored in that register and the
** result is not reusable.  If regDest<0 then this routine is free to 
** store the value whereever it wants.  The register where the expression 
** is stored is returned.  When regDest<0, two identical expressions will
** code to the same register.


*/
SQLITE_PRIVATE int sqlite3ExprCodeAtInit(
  Parse *pParse,    /* Parsing context */
  Expr *pExpr,      /* The expression to code when the VDBE initializes */
  int regDest       /* Store the value in this register */
){
  ExprList *p;
  assert( ConstFactorOk(pParse) );
  p = pParse->pConstExpr;
  if( regDest<0 && p ){
    struct ExprList_item *pItem;
    int i;
    for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
      if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){
        return pItem->u.iConstExprReg;
      }
    }
  }
  pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);














  p = sqlite3ExprListAppend(pParse, p, pExpr);
  if( p ){
     struct ExprList_item *pItem = &p->a[p->nExpr-1];
     pItem->reusable = regDest<0;
     if( regDest<0 ) regDest = ++pParse->nMem;
     pItem->u.iConstExprReg = regDest;
  }
  pParse->pConstExpr = p;

  return regDest;
}

/*
** Generate code to evaluate an expression and store the results
** into a register.  Return the register number where the results
** are stored.







|
>
>
>
>
>
>




|
|
>
>

|

















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







103202
103203
103204
103205
103206
103207
103208
103209
103210
103211
103212
103213
103214
103215
103216
103217
103218
103219
103220
103221
103222
103223
103224
103225
103226
103227
103228
103229
103230
103231
103232
103233
103234
103235
103236
103237
103238
103239
103240
103241
103242
103243
103244
103245
103246
103247
103248
103249
103250
103251
103252
103253
103254
103255
103256
103257
103258
103259
103260
103261
103262
103263
103264
103265
103266
103267
103268
103269
103270
103271
103272
  }
  sqlite3ReleaseTempReg(pParse, regFree1);
  sqlite3ReleaseTempReg(pParse, regFree2);
  return inReg;
}

/*
** Generate code that will evaluate expression pExpr just one time
** per prepared statement execution.
**
** If the expression uses functions (that might throw an exception) then
** guard them with an OP_Once opcode to ensure that the code is only executed
** once. If no functions are involved, then factor the code out and put it at
** the end of the prepared statement in the initialization section.
**
** If regDest>=0 then the result is always stored in that register and the
** result is not reusable.  If regDest<0 then this routine is free to 
** store the value whereever it wants.  The register where the expression 
** is stored is returned.  When regDest<0, two identical expressions might
** code to the same register, if they do not contain function calls and hence
** are factored out into the initialization section at the end of the
** prepared statement.
*/
SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(
  Parse *pParse,    /* Parsing context */
  Expr *pExpr,      /* The expression to code when the VDBE initializes */
  int regDest       /* Store the value in this register */
){
  ExprList *p;
  assert( ConstFactorOk(pParse) );
  p = pParse->pConstExpr;
  if( regDest<0 && p ){
    struct ExprList_item *pItem;
    int i;
    for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
      if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){
        return pItem->u.iConstExprReg;
      }
    }
  }
  pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
  if( pExpr!=0 && ExprHasProperty(pExpr, EP_HasFunc) ){
    Vdbe *v = pParse->pVdbe;
    int addr;
    assert( v );
    addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    pParse->okConstFactor = 0;
    if( !pParse->db->mallocFailed ){
      if( regDest<0 ) regDest = ++pParse->nMem;
      sqlite3ExprCode(pParse, pExpr, regDest);
    }
    pParse->okConstFactor = 1;
    sqlite3ExprDelete(pParse->db, pExpr);
    sqlite3VdbeJumpHere(v, addr);
  }else{
    p = sqlite3ExprListAppend(pParse, p, pExpr);
    if( p ){
       struct ExprList_item *pItem = &p->a[p->nExpr-1];
       pItem->reusable = regDest<0;
       if( regDest<0 ) regDest = ++pParse->nMem;
       pItem->u.iConstExprReg = regDest;
    }
    pParse->pConstExpr = p;
  }
  return regDest;
}

/*
** Generate code to evaluate an expression and store the results
** into a register.  Return the register number where the results
** are stored.
102183
102184
102185
102186
102187
102188
102189
102190
102191
102192
102193
102194
102195
102196
102197
  int r2;
  pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
  if( ConstFactorOk(pParse)
   && pExpr->op!=TK_REGISTER
   && sqlite3ExprIsConstantNotJoin(pExpr)
  ){
    *pReg  = 0;
    r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1);
  }else{
    int r1 = sqlite3GetTempReg(pParse);
    r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
    if( r2==r1 ){
      *pReg = r1;
    }else{
      sqlite3ReleaseTempReg(pParse, r1);







|







103283
103284
103285
103286
103287
103288
103289
103290
103291
103292
103293
103294
103295
103296
103297
  int r2;
  pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
  if( ConstFactorOk(pParse)
   && pExpr->op!=TK_REGISTER
   && sqlite3ExprIsConstantNotJoin(pExpr)
  ){
    *pReg  = 0;
    r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
  }else{
    int r1 = sqlite3GetTempReg(pParse);
    r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
    if( r2==r1 ){
      *pReg = r1;
    }else{
      sqlite3ReleaseTempReg(pParse, r1);
102205
102206
102207
102208
102209
102210
102211

102212
102213
102214
102215






102216
102217
102218
102219
102220
102221
102222
102223
** Generate code that will evaluate expression pExpr and store the
** results in register target.  The results are guaranteed to appear
** in register target.
*/
SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
  int inReg;


  assert( target>0 && target<=pParse->nMem );
  inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
  assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
  if( inReg!=target && pParse->pVdbe ){






    sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
  }
}

/*
** Make a transient copy of expression pExpr and then code it using
** sqlite3ExprCode().  This routine works just like sqlite3ExprCode()
** except that the input expression is guaranteed to be unchanged.







>




>
>
>
>
>
>
|







103305
103306
103307
103308
103309
103310
103311
103312
103313
103314
103315
103316
103317
103318
103319
103320
103321
103322
103323
103324
103325
103326
103327
103328
103329
103330
** Generate code that will evaluate expression pExpr and store the
** results in register target.  The results are guaranteed to appear
** in register target.
*/
SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
  int inReg;

  assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) );
  assert( target>0 && target<=pParse->nMem );
  inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
  assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
  if( inReg!=target && pParse->pVdbe ){
    u8 op;
    if( ExprHasProperty(pExpr,EP_Subquery) ){
      op = OP_Copy;
    }else{
      op = OP_SCopy;
    }
    sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target);
  }
}

/*
** Make a transient copy of expression pExpr and then code it using
** sqlite3ExprCode().  This routine works just like sqlite3ExprCode()
** except that the input expression is guaranteed to be unchanged.
102233
102234
102235
102236
102237
102238
102239
102240
102241
102242
102243
102244
102245
102246
102247
102248
102249
** Generate code that will evaluate expression pExpr and store the
** results in register target.  The results are guaranteed to appear
** in register target.  If the expression is constant, then this routine
** might choose to code the expression at initialization time.
*/
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
  if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){
    sqlite3ExprCodeAtInit(pParse, pExpr, target);
  }else{
    sqlite3ExprCode(pParse, pExpr, target);
  }
}

/*
** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target.
**







|

|







103340
103341
103342
103343
103344
103345
103346
103347
103348
103349
103350
103351
103352
103353
103354
103355
103356
** Generate code that will evaluate expression pExpr and store the
** results in register target.  The results are guaranteed to appear
** in register target.  If the expression is constant, then this routine
** might choose to code the expression at initialization time.
*/
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
  if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){
    sqlite3ExprCodeRunJustOnce(pParse, pExpr, target);
  }else{
    sqlite3ExprCodeCopy(pParse, pExpr, target);
  }
}

/*
** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target.
**
102293
102294
102295
102296
102297
102298
102299
102300
102301
102302
102303
102304
102305
102306
102307
102308

102309
102310
102311
102312
102313
102314
102315
        n--;
      }else{
        sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
      }
    }else if( (flags & SQLITE_ECEL_FACTOR)!=0
           && sqlite3ExprIsConstantNotJoin(pExpr)
    ){
      sqlite3ExprCodeAtInit(pParse, pExpr, target+i);
    }else{
      int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
      if( inReg!=target+i ){
        VdbeOp *pOp;
        if( copyOp==OP_Copy
         && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
         && pOp->p1+pOp->p3+1==inReg
         && pOp->p2+pOp->p3+1==target+i

        ){
          pOp->p3++;
        }else{
          sqlite3VdbeAddOp2(v, copyOp, inReg, target+i);
        }
      }
    }







|








>







103400
103401
103402
103403
103404
103405
103406
103407
103408
103409
103410
103411
103412
103413
103414
103415
103416
103417
103418
103419
103420
103421
103422
103423
        n--;
      }else{
        sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
      }
    }else if( (flags & SQLITE_ECEL_FACTOR)!=0
           && sqlite3ExprIsConstantNotJoin(pExpr)
    ){
      sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
    }else{
      int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
      if( inReg!=target+i ){
        VdbeOp *pOp;
        if( copyOp==OP_Copy
         && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
         && pOp->p1+pOp->p3+1==inReg
         && pOp->p2+pOp->p3+1==target+i
         && pOp->p5==0  /* The do-not-merge flag must be clear */
        ){
          pOp->p3++;
        }else{
          sqlite3VdbeAddOp2(v, copyOp, inReg, target+i);
        }
      }
    }
102415
102416
102417
102418
102419
102420
102421

102422
102423
102424
102425
102426
102427
102428
  int regFree1 = 0;
  int regFree2 = 0;
  int r1, r2;

  assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
  if( NEVER(v==0) )     return;  /* Existence of VDBE checked by caller */
  if( NEVER(pExpr==0) ) return;  /* No way this can happen */

  op = pExpr->op;
  switch( op ){
    case TK_AND:
    case TK_OR: {
      Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr);
      if( pAlt!=pExpr ){
        sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull);







>







103523
103524
103525
103526
103527
103528
103529
103530
103531
103532
103533
103534
103535
103536
103537
  int regFree1 = 0;
  int regFree2 = 0;
  int r1, r2;

  assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
  if( NEVER(v==0) )     return;  /* Existence of VDBE checked by caller */
  if( NEVER(pExpr==0) ) return;  /* No way this can happen */
  assert( !ExprHasVVAProperty(pExpr, EP_Immutable) );
  op = pExpr->op;
  switch( op ){
    case TK_AND:
    case TK_OR: {
      Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr);
      if( pAlt!=pExpr ){
        sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull);
102556
102557
102558
102559
102560
102561
102562

102563
102564
102565
102566
102567
102568
102569
  int regFree1 = 0;
  int regFree2 = 0;
  int r1, r2;

  assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
  if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
  if( pExpr==0 )    return;


  /* The value of pExpr->op and op are related as follows:
  **
  **       pExpr->op            op
  **       ---------          ----------
  **       TK_ISNULL          OP_NotNull
  **       TK_NOTNULL         OP_IsNull







>







103665
103666
103667
103668
103669
103670
103671
103672
103673
103674
103675
103676
103677
103678
103679
  int regFree1 = 0;
  int regFree2 = 0;
  int r1, r2;

  assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
  if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
  if( pExpr==0 )    return;
  assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );

  /* The value of pExpr->op and op are related as follows:
  **
  **       pExpr->op            op
  **       ---------          ----------
  **       TK_ISNULL          OP_NotNull
  **       TK_NOTNULL         OP_IsNull
102839
102840
102841
102842
102843
102844
102845
102846
102847
102848
102849
102850
102851
102852
102853
102854
102855
102856
102857
102858
102859
102860
102861
102862
102863
102864
102865
102866
102867
102868
102869
102870
102871
102872
102873
102874
102875
102876
102877
102878
102879
102880
102881
102882

102883
102884
102885
102886
102887
102888
102889
102890
102891
102892
102893
102894
102895
102896
102897
102898
102899
102900

102901
102902
102903
102904
102905
102906
102907
102908
102909
102910
102911
      if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
    }else if( ALWAYS(pB->u.zToken!=0) && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
      return 2;
    }
  }
  if( (pA->flags & (EP_Distinct|EP_Commuted))
     != (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2;
  if( (combinedFlags & EP_TokenOnly)==0 ){
    if( combinedFlags & EP_xIsSelect ) return 2;
    if( (combinedFlags & EP_FixedCol)==0
     && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
    if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2;
    if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
    if( pA->op!=TK_STRING
     && pA->op!=TK_TRUEFALSE
     && (combinedFlags & EP_Reduced)==0
    ){
      if( pA->iColumn!=pB->iColumn ) return 2;
      if( pA->op2!=pB->op2 ){
        if( pA->op==TK_TRUTH ) return 2;
        if( pA->op==TK_FUNCTION && iTab<0 ){
          /* Ex: CREATE TABLE t1(a CHECK( a<julianday('now') ));
          **     INSERT INTO t1(a) VALUES(julianday('now')+10);
          ** Without this test, sqlite3ExprCodeAtInit() will run on the
          ** the julianday() of INSERT first, and remember that expression.
          ** Then sqlite3ExprCodeInit() will see the julianday() in the CHECK
          ** constraint as redundant, reusing the one from the INSERT, even
          ** though the julianday() in INSERT lacks the critical NC_IsCheck
          ** flag.  See ticket [830277d9db6c3ba1] (2019-10-30)
          */
          return 2;
        }
      }
      if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){
        return 2;
      }
    }
  }
  return 0;
}

/*
** Compare two ExprList objects.  Return 0 if they are identical and 
** non-zero if they differ in any way.

**
** If any subelement of pB has Expr.iTable==(-1) then it is allowed
** to compare equal to an equivalent element in pA with Expr.iTable==iTab.
**
** This routine might return non-zero for equivalent ExprLists.  The
** only consequence will be disabled optimizations.  But this routine
** must never return 0 if the two ExprList objects are different, or
** a malfunction will result.
**
** Two NULL pointers are considered to be the same.  But a NULL pointer
** always differs from a non-NULL pointer.
*/
SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
  int i;
  if( pA==0 && pB==0 ) return 0;
  if( pA==0 || pB==0 ) return 1;
  if( pA->nExpr!=pB->nExpr ) return 1;
  for(i=0; i<pA->nExpr; i++){

    Expr *pExprA = pA->a[i].pExpr;
    Expr *pExprB = pB->a[i].pExpr;
    if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
    if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1;
  }
  return 0;
}

/*
** Like sqlite3ExprCompare() except COLLATE operators at the top-level
** are ignored.







|







|


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









|
|
>


















>



|







103949
103950
103951
103952
103953
103954
103955
103956
103957
103958
103959
103960
103961
103962
103963
103964
103965
103966
103967














103968
103969
103970
103971
103972
103973
103974
103975
103976
103977
103978
103979
103980
103981
103982
103983
103984
103985
103986
103987
103988
103989
103990
103991
103992
103993
103994
103995
103996
103997
103998
103999
104000
104001
104002
104003
104004
104005
104006
104007
104008
104009
      if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
    }else if( ALWAYS(pB->u.zToken!=0) && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
      return 2;
    }
  }
  if( (pA->flags & (EP_Distinct|EP_Commuted))
     != (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2;
  if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){
    if( combinedFlags & EP_xIsSelect ) return 2;
    if( (combinedFlags & EP_FixedCol)==0
     && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
    if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2;
    if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
    if( pA->op!=TK_STRING
     && pA->op!=TK_TRUEFALSE
     && ALWAYS((combinedFlags & EP_Reduced)==0)
    ){
      if( pA->iColumn!=pB->iColumn ) return 2;
      if( pA->op2!=pB->op2 && pA->op==TK_TRUTH ) return 2;














      if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){
        return 2;
      }
    }
  }
  return 0;
}

/*
** Compare two ExprList objects.  Return 0 if they are identical, 1
** if they are certainly different, or 2 if it is not possible to 
** determine if they are identical or not.
**
** If any subelement of pB has Expr.iTable==(-1) then it is allowed
** to compare equal to an equivalent element in pA with Expr.iTable==iTab.
**
** This routine might return non-zero for equivalent ExprLists.  The
** only consequence will be disabled optimizations.  But this routine
** must never return 0 if the two ExprList objects are different, or
** a malfunction will result.
**
** Two NULL pointers are considered to be the same.  But a NULL pointer
** always differs from a non-NULL pointer.
*/
SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
  int i;
  if( pA==0 && pB==0 ) return 0;
  if( pA==0 || pB==0 ) return 1;
  if( pA->nExpr!=pB->nExpr ) return 1;
  for(i=0; i<pA->nExpr; i++){
    int res;
    Expr *pExprA = pA->a[i].pExpr;
    Expr *pExprB = pB->a[i].pExpr;
    if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
    if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res;
  }
  return 0;
}

/*
** Like sqlite3ExprCompare() except COLLATE operators at the top-level
** are ignored.
103076
103077
103078
103079
103080
103081
103082
103083
103084
103085
103086
103087

103088
103089
103090
103091
103092



103093
103094
103095
103096
103097
103098
103099
103100
103101
103102
103103


103104
103105
103106
103107
103108
103109


103110

103111

103112
103113
103114
103115
103116
103117
103118
103119
103120
103121
103122
      if( pWalker->u.iCur==pExpr->iTable ){
        pWalker->eCode = 1;
        return WRC_Abort;
      }
      return WRC_Prune;

    case TK_AND:
      assert( pWalker->eCode==0 );
      sqlite3WalkExpr(pWalker, pExpr->pLeft);
      if( pWalker->eCode ){
        pWalker->eCode = 0;
        sqlite3WalkExpr(pWalker, pExpr->pRight);

      }
      return WRC_Prune;

    case TK_BETWEEN:
      sqlite3WalkExpr(pWalker, pExpr->pLeft);



      return WRC_Prune;

    /* Virtual tables are allowed to use constraints like x=NULL.  So
    ** a term of the form x=y does not prove that y is not null if x
    ** is the column of a virtual table */
    case TK_EQ:
    case TK_NE:
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE:


      testcase( pExpr->op==TK_EQ );
      testcase( pExpr->op==TK_NE );
      testcase( pExpr->op==TK_LT );
      testcase( pExpr->op==TK_LE );
      testcase( pExpr->op==TK_GT );
      testcase( pExpr->op==TK_GE );


      if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->y.pTab))

       || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->y.pTab))

      ){
       return WRC_Prune;
      }

    default:
      return WRC_Continue;
  }
}

/*
** Return true (non-zero) if expression p can only be true if at least







|
|
|
|
|
>




|
>
>
>










|
>
>






>
>
|
>
|
>

|

|







104174
104175
104176
104177
104178
104179
104180
104181
104182
104183
104184
104185
104186
104187
104188
104189
104190
104191
104192
104193
104194
104195
104196
104197
104198
104199
104200
104201
104202
104203
104204
104205
104206
104207
104208
104209
104210
104211
104212
104213
104214
104215
104216
104217
104218
104219
104220
104221
104222
104223
104224
104225
104226
104227
104228
104229
104230
      if( pWalker->u.iCur==pExpr->iTable ){
        pWalker->eCode = 1;
        return WRC_Abort;
      }
      return WRC_Prune;

    case TK_AND:
      if( pWalker->eCode==0 ){
        sqlite3WalkExpr(pWalker, pExpr->pLeft);
        if( pWalker->eCode ){
          pWalker->eCode = 0;
          sqlite3WalkExpr(pWalker, pExpr->pRight);
        }
      }
      return WRC_Prune;

    case TK_BETWEEN:
      if( sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){
        assert( pWalker->eCode );
        return WRC_Abort;
      }
      return WRC_Prune;

    /* Virtual tables are allowed to use constraints like x=NULL.  So
    ** a term of the form x=y does not prove that y is not null if x
    ** is the column of a virtual table */
    case TK_EQ:
    case TK_NE:
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE: {
      Expr *pLeft = pExpr->pLeft;
      Expr *pRight = pExpr->pRight;
      testcase( pExpr->op==TK_EQ );
      testcase( pExpr->op==TK_NE );
      testcase( pExpr->op==TK_LT );
      testcase( pExpr->op==TK_LE );
      testcase( pExpr->op==TK_GT );
      testcase( pExpr->op==TK_GE );
      /* The y.pTab=0 assignment in wherecode.c always happens after the
      ** impliesNotNullRow() test */
      if( (pLeft->op==TK_COLUMN && ALWAYS(pLeft->y.pTab!=0)
                               && IsVirtual(pLeft->y.pTab))
       || (pRight->op==TK_COLUMN && ALWAYS(pRight->y.pTab!=0)
                               && IsVirtual(pRight->y.pTab))
      ){
        return WRC_Prune;
      }
    }
    default:
      return WRC_Continue;
  }
}

/*
** Return true (non-zero) if expression p can only be true if at least
103228
103229
103230
103231
103232
103233
103234

103235
103236
103237

103238
103239
103240
103241
103242
103243
103244
103245
103246
103247
  int nOther;      /* Number of references to columns in other FROM clauses */
};

/*
** Count the number of references to columns.
*/
static int exprSrcCount(Walker *pWalker, Expr *pExpr){

  /* The NEVER() on the second term is because sqlite3FunctionUsesThisSrc()
  ** is always called before sqlite3ExprAnalyzeAggregates() and so the
  ** TK_COLUMNs have not yet been converted into TK_AGG_COLUMN.  If

  ** sqlite3FunctionUsesThisSrc() is used differently in the future, the
  ** NEVER() will need to be removed. */
  if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){
    int i;
    struct SrcCount *p = pWalker->u.pSrcCount;
    SrcList *pSrc = p->pSrc;
    int nSrc = pSrc ? pSrc->nSrc : 0;
    for(i=0; i<nSrc; i++){
      if( pExpr->iTable==pSrc->a[i].iCursor ) break;
    }







>
|
|
|
>
|
<
|







104336
104337
104338
104339
104340
104341
104342
104343
104344
104345
104346
104347
104348

104349
104350
104351
104352
104353
104354
104355
104356
  int nOther;      /* Number of references to columns in other FROM clauses */
};

/*
** Count the number of references to columns.
*/
static int exprSrcCount(Walker *pWalker, Expr *pExpr){
  /* There was once a NEVER() on the second term on the grounds that
  ** sqlite3FunctionUsesThisSrc() was always called before 
  ** sqlite3ExprAnalyzeAggregates() and so the TK_COLUMNs have not yet 
  ** been converted into TK_AGG_COLUMN. But this is no longer true due
  ** to window functions - sqlite3WindowRewrite() may now indirectly call
  ** FunctionUsesThisSrc() when creating a new sub-select. */

  if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
    int i;
    struct SrcCount *p = pWalker->u.pSrcCount;
    SrcList *pSrc = p->pSrc;
    int nSrc = pSrc ? pSrc->nSrc : 0;
    for(i=0; i<nSrc; i++){
      if( pExpr->iTable==pSrc->a[i].iCursor ) break;
    }
103271
103272
103273
103274
103275
103276
103277





103278
103279
103280
103281
103282
103283
103284
  w.xExprCallback = exprSrcCount;
  w.xSelectCallback = sqlite3SelectWalkNoop;
  w.u.pSrcCount = &cnt;
  cnt.pSrc = pSrcList;
  cnt.nThis = 0;
  cnt.nOther = 0;
  sqlite3WalkExprList(&w, pExpr->x.pList);





  return cnt.nThis>0 || cnt.nOther==0;
}

/*
** Add a new element to the pAggInfo->aCol[] array.  Return the index of
** the new element.  Return a negative number if malloc fails.
*/







>
>
>
>
>







104380
104381
104382
104383
104384
104385
104386
104387
104388
104389
104390
104391
104392
104393
104394
104395
104396
104397
104398
  w.xExprCallback = exprSrcCount;
  w.xSelectCallback = sqlite3SelectWalkNoop;
  w.u.pSrcCount = &cnt;
  cnt.pSrc = pSrcList;
  cnt.nThis = 0;
  cnt.nOther = 0;
  sqlite3WalkExprList(&w, pExpr->x.pList);
#ifndef SQLITE_OMIT_WINDOWFUNC
  if( ExprHasProperty(pExpr, EP_WinFunc) ){
    sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
  }
#endif
  return cnt.nThis>0 || cnt.nOther==0;
}

/*
** Add a new element to the pAggInfo->aCol[] array.  Return the index of
** the new element.  Return a negative number if malloc fails.
*/
103499
103500
103501
103502
103503
103504
103505


103506
103507

103508
103509
103510
103511
103512
103513
103514
}

/*
** Deallocate a register, making available for reuse for some other
** purpose.
*/
SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){


  if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
    pParse->aTempReg[pParse->nTempReg++] = iReg;

  }
}

/*
** Allocate or deallocate a block of nReg consecutive registers.
*/
SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){







>
>
|
|
>







104613
104614
104615
104616
104617
104618
104619
104620
104621
104622
104623
104624
104625
104626
104627
104628
104629
104630
104631
}

/*
** Deallocate a register, making available for reuse for some other
** purpose.
*/
SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
  if( iReg ){
    sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0);
    if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
      pParse->aTempReg[pParse->nTempReg++] = iReg;
    }
  }
}

/*
** Allocate or deallocate a block of nReg consecutive registers.
*/
SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
103526
103527
103528
103529
103530
103531
103532

103533
103534
103535
103536
103537
103538
103539
  return i;
}
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
  if( nReg==1 ){
    sqlite3ReleaseTempReg(pParse, iReg);
    return;
  }

  if( nReg>pParse->nRangeReg ){
    pParse->nRangeReg = nReg;
    pParse->iRangeReg = iReg;
  }
}

/*







>







104643
104644
104645
104646
104647
104648
104649
104650
104651
104652
104653
104654
104655
104656
104657
  return i;
}
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
  if( nReg==1 ){
    sqlite3ReleaseTempReg(pParse, iReg);
    return;
  }
  sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0, 0);
  if( nReg>pParse->nRangeReg ){
    pParse->nRangeReg = nReg;
    pParse->iRangeReg = iReg;
  }
}

/*
104041
104042
104043
104044
104045
104046
104047

104048
104049
104050
104051
104052
104053
104054
    assert( db->mallocFailed );
    goto exit_begin_add_column;
  }
  memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
  for(i=0; i<pNew->nCol; i++){
    Column *pCol = &pNew->aCol[i];
    pCol->zName = sqlite3DbStrDup(db, pCol->zName);

    pCol->zColl = 0;
    pCol->pDflt = 0;
  }
  pNew->pSchema = db->aDb[iDb].pSchema;
  pNew->addColOffset = pTab->addColOffset;
  pNew->nTabRef = 1;








>







105159
105160
105161
105162
105163
105164
105165
105166
105167
105168
105169
105170
105171
105172
105173
    assert( db->mallocFailed );
    goto exit_begin_add_column;
  }
  memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
  for(i=0; i<pNew->nCol; i++){
    Column *pCol = &pNew->aCol[i];
    pCol->zName = sqlite3DbStrDup(db, pCol->zName);
    pCol->hName = sqlite3StrIHash(pCol->zName);
    pCol->zColl = 0;
    pCol->pDflt = 0;
  }
  pNew->pSchema = db->aDb[iDb].pSchema;
  pNew->addColOffset = pTab->addColOffset;
  pNew->nTabRef = 1;

104269
104270
104271
104272
104273
104274
104275

104276
104277
104278
104279
104280
104281

104282
104283
104284
104285
104286
104287
104288
** with tail recursion in tokenExpr() routine, for a small performance
** improvement.
*/
SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
  RenameToken *pNew;
  assert( pPtr || pParse->db->mallocFailed );
  renameTokenCheckAll(pParse, pPtr);

  pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
  if( pNew ){
    pNew->p = pPtr;
    pNew->t = *pToken;
    pNew->pNext = pParse->pRename;
    pParse->pRename = pNew;

  }

  return pPtr;
}

/*
** It is assumed that there is already a RenameToken object associated







>
|
|
|
|
|
|
>







105388
105389
105390
105391
105392
105393
105394
105395
105396
105397
105398
105399
105400
105401
105402
105403
105404
105405
105406
105407
105408
105409
** with tail recursion in tokenExpr() routine, for a small performance
** improvement.
*/
SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
  RenameToken *pNew;
  assert( pPtr || pParse->db->mallocFailed );
  renameTokenCheckAll(pParse, pPtr);
  if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){
    pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
    if( pNew ){
      pNew->p = pPtr;
      pNew->t = *pToken;
      pNew->pNext = pParse->pRename;
      pParse->pRename = pNew;
    }
  }

  return pPtr;
}

/*
** It is assumed that there is already a RenameToken object associated
104304
104305
104306
104307
104308
104309
104310



































104311
104312
104313
104314
104315
104316
104317


104318
104319
104320
104321
104322
104323
104324
104325
104326
104327
104328
104329


104330
104331


104332
104333
104334
104335
104336
104337
104338

104339
104340
104341
104342
104343

104344

104345
104346
104347
104348
104349
104350
104351
104352
104353
104354
104355
104356
104357
104358
104359

104360

104361
104362
104363
104364
104365
104366
104367
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
  Parse *pParse = pWalker->pParse;
  sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
  return WRC_Continue;
}




































/*
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapSelectCb(Walker *pWalker, Select *p){
  Parse *pParse = pWalker->pParse;
  int i;


  if( ALWAYS(p->pEList) ){
    ExprList *pList = p->pEList;
    for(i=0; i<pList->nExpr; i++){
      if( pList->a[i].zName ){
        sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zName);
      }
    }
  }
  if( ALWAYS(p->pSrc) ){  /* Every Select as a SrcList, even if it is empty */
    SrcList *pSrc = p->pSrc;
    for(i=0; i<pSrc->nSrc; i++){
      sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);


    }
  }


  return WRC_Continue;
}

/*
** Remove all nodes that are part of expression pExpr from the rename list.
*/
SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){

  Walker sWalker;
  memset(&sWalker, 0, sizeof(Walker));
  sWalker.pParse = pParse;
  sWalker.xExprCallback = renameUnmapExprCb;
  sWalker.xSelectCallback = renameUnmapSelectCb;

  sqlite3WalkExpr(&sWalker, pExpr);

}

/*
** Remove all nodes that are part of expression-list pEList from the 
** rename list.
*/
SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
  if( pEList ){
    int i;
    Walker sWalker;
    memset(&sWalker, 0, sizeof(Walker));
    sWalker.pParse = pParse;
    sWalker.xExprCallback = renameUnmapExprCb;
    sqlite3WalkExprList(&sWalker, pEList);
    for(i=0; i<pEList->nExpr; i++){

      sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName);

    }
  }
}

/*
** Free the list of RenameToken objects given in the second argument
*/







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







>
>



|
|







>
>


>
>







>





>

>















>
|
>







105425
105426
105427
105428
105429
105430
105431
105432
105433
105434
105435
105436
105437
105438
105439
105440
105441
105442
105443
105444
105445
105446
105447
105448
105449
105450
105451
105452
105453
105454
105455
105456
105457
105458
105459
105460
105461
105462
105463
105464
105465
105466
105467
105468
105469
105470
105471
105472
105473
105474
105475
105476
105477
105478
105479
105480
105481
105482
105483
105484
105485
105486
105487
105488
105489
105490
105491
105492
105493
105494
105495
105496
105497
105498
105499
105500
105501
105502
105503
105504
105505
105506
105507
105508
105509
105510
105511
105512
105513
105514
105515
105516
105517
105518
105519
105520
105521
105522
105523
105524
105525
105526
105527
105528
105529
105530
105531
105532
105533
105534
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
  Parse *pParse = pWalker->pParse;
  sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
  return WRC_Continue;
}

/*
** Iterate through the Select objects that are part of WITH clauses attached
** to select statement pSelect.
*/
static void renameWalkWith(Walker *pWalker, Select *pSelect){
  With *pWith = pSelect->pWith;
  if( pWith ){
    int i;
    for(i=0; i<pWith->nCte; i++){
      Select *p = pWith->a[i].pSelect;
      NameContext sNC;
      memset(&sNC, 0, sizeof(sNC));
      sNC.pParse = pWalker->pParse;
      sqlite3SelectPrep(sNC.pParse, p, &sNC);
      sqlite3WalkSelect(pWalker, p);
      sqlite3RenameExprlistUnmap(pWalker->pParse, pWith->a[i].pCols);
    }
  }
}

/*
** Unmap all tokens in the IdList object passed as the second argument.
*/
static void unmapColumnIdlistNames(
  Parse *pParse,
  IdList *pIdList
){
  if( pIdList ){
    int ii;
    for(ii=0; ii<pIdList->nId; ii++){
      sqlite3RenameTokenRemap(pParse, 0, (void*)pIdList->a[ii].zName);
    }
  }
}

/*
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapSelectCb(Walker *pWalker, Select *p){
  Parse *pParse = pWalker->pParse;
  int i;
  if( pParse->nErr ) return WRC_Abort;
  if( NEVER(p->selFlags & SF_View) ) return WRC_Prune;
  if( ALWAYS(p->pEList) ){
    ExprList *pList = p->pEList;
    for(i=0; i<pList->nExpr; i++){
      if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
        sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
      }
    }
  }
  if( ALWAYS(p->pSrc) ){  /* Every Select as a SrcList, even if it is empty */
    SrcList *pSrc = p->pSrc;
    for(i=0; i<pSrc->nSrc; i++){
      sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
      if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort;
      unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
    }
  }

  renameWalkWith(pWalker, p);
  return WRC_Continue;
}

/*
** Remove all nodes that are part of expression pExpr from the rename list.
*/
SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){
  u8 eMode = pParse->eParseMode;
  Walker sWalker;
  memset(&sWalker, 0, sizeof(Walker));
  sWalker.pParse = pParse;
  sWalker.xExprCallback = renameUnmapExprCb;
  sWalker.xSelectCallback = renameUnmapSelectCb;
  pParse->eParseMode = PARSE_MODE_UNMAP;
  sqlite3WalkExpr(&sWalker, pExpr);
  pParse->eParseMode = eMode;
}

/*
** Remove all nodes that are part of expression-list pEList from the 
** rename list.
*/
SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
  if( pEList ){
    int i;
    Walker sWalker;
    memset(&sWalker, 0, sizeof(Walker));
    sWalker.pParse = pParse;
    sWalker.xExprCallback = renameUnmapExprCb;
    sqlite3WalkExprList(&sWalker, pEList);
    for(i=0; i<pEList->nExpr; i++){
      if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){
        sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName);
      }
    }
  }
}

/*
** Free the list of RenameToken objects given in the second argument
*/
104391
104392
104393
104394
104395
104396
104397
104398
104399
104400
104401
104402
104403
104404
104405
104406
104407
104408
104409
104410
104411
104412
104413
104414
104415
104416
104417
104418
104419
104420
104421

104422
104423
104424
104425
104426
104427
104428
      pCtx->pList = pToken;
      pCtx->nList++;
      break;
    }
  }
}

/*
** Iterate through the Select objects that are part of WITH clauses attached
** to select statement pSelect.
*/
static void renameWalkWith(Walker *pWalker, Select *pSelect){
  if( pSelect->pWith ){
    int i;
    for(i=0; i<pSelect->pWith->nCte; i++){
      Select *p = pSelect->pWith->a[i].pSelect;
      NameContext sNC;
      memset(&sNC, 0, sizeof(sNC));
      sNC.pParse = pWalker->pParse;
      sqlite3SelectPrep(sNC.pParse, p, &sNC);
      sqlite3WalkSelect(pWalker, p);
    }
  }
}

/*
** This is a Walker select callback. It does nothing. It is only required
** because without a dummy callback, sqlite3WalkExpr() and similar do not
** descend into sub-select statements.
*/
static int renameColumnSelectCb(Walker *pWalker, Select *p){

  renameWalkWith(pWalker, p);
  return WRC_Continue;
}

/*
** This is a Walker expression callback.
**







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






>







105558
105559
105560
105561
105562
105563
105564


















105565
105566
105567
105568
105569
105570
105571
105572
105573
105574
105575
105576
105577
105578
      pCtx->pList = pToken;
      pCtx->nList++;
      break;
    }
  }
}



















/*
** This is a Walker select callback. It does nothing. It is only required
** because without a dummy callback, sqlite3WalkExpr() and similar do not
** descend into sub-select statements.
*/
static int renameColumnSelectCb(Walker *pWalker, Select *p){
  if( p->selFlags & SF_View ) return WRC_Prune;
  renameWalkWith(pWalker, p);
  return WRC_Continue;
}

/*
** This is a Walker expression callback.
**
104508
104509
104510
104511
104512
104513
104514
104515


104516

104517
104518
104519
104520
104521
104522
104523
  RenameCtx *pCtx, 
  ExprList *pEList, 
  const char *zOld
){
  if( pEList ){
    int i;
    for(i=0; i<pEList->nExpr; i++){
      char *zName = pEList->a[i].zName;


      if( 0==sqlite3_stricmp(zName, zOld) ){

        renameTokenFind(pParse, pCtx, (void*)zName);
      }
    }
  }
}

/*







|
>
>
|
>







105658
105659
105660
105661
105662
105663
105664
105665
105666
105667
105668
105669
105670
105671
105672
105673
105674
105675
105676
  RenameCtx *pCtx, 
  ExprList *pEList, 
  const char *zOld
){
  if( pEList ){
    int i;
    for(i=0; i<pEList->nExpr; i++){
      char *zName = pEList->a[i].zEName;
      if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
       && ALWAYS(zName!=0)
       && 0==sqlite3_stricmp(zName, zOld)
      ){
        renameTokenFind(pParse, pCtx, (void*)zName);
      }
    }
  }
}

/*
104537
104538
104539
104540
104541
104542
104543

104544
104545
104546
104547
104548
104549
104550
104551
104552
104553
104554
104555
104556
104557
104558
104559
104560
104561
104562
104563
104564
104565
104566
104567
104568
104569
104570
104571
104572
104573
      char *zName = pIdList->a[i].zName;
      if( 0==sqlite3_stricmp(zName, zOld) ){
        renameTokenFind(pParse, pCtx, (void*)zName);
      }
    }
  }
}


/*
** Parse the SQL statement zSql using Parse object (*p). The Parse object
** is initialized by this function before it is used.
*/
static int renameParseSql(
  Parse *p,                       /* Memory to use for Parse object */
  const char *zDb,                /* Name of schema SQL belongs to */
  int bTable,                     /* 1 -> RENAME TABLE, 0 -> RENAME COLUMN */
  sqlite3 *db,                    /* Database handle */
  const char *zSql,               /* SQL to parse */
  int bTemp                       /* True if SQL is from temp schema */
){
  int rc;
  char *zErr = 0;

  db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);

  /* Parse the SQL statement passed as the first argument. If no error
  ** occurs and the parse does not result in a new table, index or
  ** trigger object, the database must be corrupt. */
  memset(p, 0, sizeof(Parse));
  p->eParseMode = (bTable ? PARSE_MODE_RENAME_TABLE : PARSE_MODE_RENAME_COLUMN);
  p->db = db;
  p->nQueryLoop = 1;
  rc = sqlite3RunParser(p, zSql, &zErr);
  assert( p->zErrMsg==0 );
  assert( rc!=SQLITE_OK || zErr==0 );
  p->zErrMsg = zErr;
  if( db->mallocFailed ) rc = SQLITE_NOMEM;







>








<













|







105690
105691
105692
105693
105694
105695
105696
105697
105698
105699
105700
105701
105702
105703
105704
105705

105706
105707
105708
105709
105710
105711
105712
105713
105714
105715
105716
105717
105718
105719
105720
105721
105722
105723
105724
105725
105726
      char *zName = pIdList->a[i].zName;
      if( 0==sqlite3_stricmp(zName, zOld) ){
        renameTokenFind(pParse, pCtx, (void*)zName);
      }
    }
  }
}


/*
** Parse the SQL statement zSql using Parse object (*p). The Parse object
** is initialized by this function before it is used.
*/
static int renameParseSql(
  Parse *p,                       /* Memory to use for Parse object */
  const char *zDb,                /* Name of schema SQL belongs to */

  sqlite3 *db,                    /* Database handle */
  const char *zSql,               /* SQL to parse */
  int bTemp                       /* True if SQL is from temp schema */
){
  int rc;
  char *zErr = 0;

  db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);

  /* Parse the SQL statement passed as the first argument. If no error
  ** occurs and the parse does not result in a new table, index or
  ** trigger object, the database must be corrupt. */
  memset(p, 0, sizeof(Parse));
  p->eParseMode = PARSE_MODE_RENAME;
  p->db = db;
  p->nQueryLoop = 1;
  rc = sqlite3RunParser(p, zSql, &zErr);
  assert( p->zErrMsg==0 );
  assert( rc!=SQLITE_OK || zErr==0 );
  p->zErrMsg = zErr;
  if( db->mallocFailed ) rc = SQLITE_NOMEM;
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
  zOld = pTab->aCol[iCol].zName;
  memset(&sCtx, 0, sizeof(sCtx));
  sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);

#ifndef SQLITE_OMIT_AUTHORIZATION
  db->xAuth = 0;
#endif
  rc = renameParseSql(&sParse, zDb, 0, db, zSql, bTemp);

  /* Find tokens that need to be replaced. */
  memset(&sWalker, 0, sizeof(Walker));
  sWalker.pParse = &sParse;
  sWalker.xExprCallback = renameColumnExprCb;
  sWalker.xSelectCallback = renameColumnSelectCb;
  sWalker.u.pRename = &sCtx;

  sCtx.pTab = pTab;
  if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
  if( sParse.pNewTable ){
    Select *pSelect = sParse.pNewTable->pSelect;
    if( pSelect ){

      sParse.rc = SQLITE_OK;
      sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0);
      rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
      if( rc==SQLITE_OK ){
        sqlite3WalkSelect(&sWalker, pSelect);
      }
      if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
    }else{
      /* A regular table */







|













>

|







106019
106020
106021
106022
106023
106024
106025
106026
106027
106028
106029
106030
106031
106032
106033
106034
106035
106036
106037
106038
106039
106040
106041
106042
106043
106044
106045
106046
106047
106048
106049
  zOld = pTab->aCol[iCol].zName;
  memset(&sCtx, 0, sizeof(sCtx));
  sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);

#ifndef SQLITE_OMIT_AUTHORIZATION
  db->xAuth = 0;
#endif
  rc = renameParseSql(&sParse, zDb, db, zSql, bTemp);

  /* Find tokens that need to be replaced. */
  memset(&sWalker, 0, sizeof(Walker));
  sWalker.pParse = &sParse;
  sWalker.xExprCallback = renameColumnExprCb;
  sWalker.xSelectCallback = renameColumnSelectCb;
  sWalker.u.pRename = &sCtx;

  sCtx.pTab = pTab;
  if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
  if( sParse.pNewTable ){
    Select *pSelect = sParse.pNewTable->pSelect;
    if( pSelect ){
      pSelect->selFlags &= ~SF_View;
      sParse.rc = SQLITE_OK;
      sqlite3SelectPrep(&sParse, pSelect, 0);
      rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
      if( rc==SQLITE_OK ){
        sqlite3WalkSelect(&sWalker, pSelect);
      }
      if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
    }else{
      /* A regular table */
104998
104999
105000
105001
105002
105003
105004

105005
105006
105007
105008
105009
105010
105011
/*
** Walker select callback used by "RENAME TABLE". 
*/
static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
  int i;
  RenameCtx *p = pWalker->u.pRename;
  SrcList *pSrc = pSelect->pSrc;

  if( pSrc==0 ){
    assert( pWalker->pParse->db->mallocFailed );
    return WRC_Abort;
  }
  for(i=0; i<pSrc->nSrc; i++){
    struct SrcList_item *pItem = &pSrc->a[i];
    if( pItem->pTab==p->pTab ){







>







106152
106153
106154
106155
106156
106157
106158
106159
106160
106161
106162
106163
106164
106165
106166
/*
** Walker select callback used by "RENAME TABLE". 
*/
static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
  int i;
  RenameCtx *p = pWalker->u.pRename;
  SrcList *pSrc = pSelect->pSrc;
  if( pSelect->selFlags & SF_View ) return WRC_Prune;
  if( pSrc==0 ){
    assert( pWalker->pParse->db->mallocFailed );
    return WRC_Abort;
  }
  for(i=0; i<pSrc->nSrc; i++){
    struct SrcList_item *pItem = &pSrc->a[i];
    if( pItem->pTab==p->pTab ){
105068
105069
105070
105071
105072
105073
105074
105075
105076
105077
105078
105079
105080
105081
105082
105083

105084
105085
105086
105087


105088
105089


105090

105091
105092
105093
105094
105095
105096
105097
    sCtx.pTab = sqlite3FindTable(db, zOld, zDb);
    memset(&sWalker, 0, sizeof(Walker));
    sWalker.pParse = &sParse;
    sWalker.xExprCallback = renameTableExprCb;
    sWalker.xSelectCallback = renameTableSelectCb;
    sWalker.u.pRename = &sCtx;

    rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);

    if( rc==SQLITE_OK ){
      int isLegacy = (db->flags & SQLITE_LegacyAlter);
      if( sParse.pNewTable ){
        Table *pTab = sParse.pNewTable;

        if( pTab->pSelect ){
          if( isLegacy==0 ){

            NameContext sNC;
            memset(&sNC, 0, sizeof(sNC));
            sNC.pParse = &sParse;



            sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
            if( sParse.nErr ) rc = sParse.rc;


            sqlite3WalkSelect(&sWalker, pTab->pSelect);

          }
        }else{
          /* Modify any FK definitions to point to the new table. */
#ifndef SQLITE_OMIT_FOREIGN_KEY
          if( isLegacy==0 || (db->flags & SQLITE_ForeignKeys) ){
            FKey *pFKey;
            for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){







|








>




>
>

|
>
>
|
>







106223
106224
106225
106226
106227
106228
106229
106230
106231
106232
106233
106234
106235
106236
106237
106238
106239
106240
106241
106242
106243
106244
106245
106246
106247
106248
106249
106250
106251
106252
106253
106254
106255
106256
106257
106258
    sCtx.pTab = sqlite3FindTable(db, zOld, zDb);
    memset(&sWalker, 0, sizeof(Walker));
    sWalker.pParse = &sParse;
    sWalker.xExprCallback = renameTableExprCb;
    sWalker.xSelectCallback = renameTableSelectCb;
    sWalker.u.pRename = &sCtx;

    rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);

    if( rc==SQLITE_OK ){
      int isLegacy = (db->flags & SQLITE_LegacyAlter);
      if( sParse.pNewTable ){
        Table *pTab = sParse.pNewTable;

        if( pTab->pSelect ){
          if( isLegacy==0 ){
            Select *pSelect = pTab->pSelect;
            NameContext sNC;
            memset(&sNC, 0, sizeof(sNC));
            sNC.pParse = &sParse;

            assert( pSelect->selFlags & SF_View );
            pSelect->selFlags &= ~SF_View;
            sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
            if( sParse.nErr ){
              rc = sParse.rc;
            }else{
              sqlite3WalkSelect(&sWalker, pTab->pSelect);
            }
          }
        }else{
          /* Modify any FK definitions to point to the new table. */
#ifndef SQLITE_OMIT_FOREIGN_KEY
          if( isLegacy==0 || (db->flags & SQLITE_ForeignKeys) ){
            FKey *pFKey;
            for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
105204
105205
105206
105207
105208
105209
105210
105211
105212
105213
105214
105215
105216
105217
105218
  db->xAuth = 0;
#endif

  UNUSED_PARAMETER(NotUsed);
  if( zDb && zInput ){
    int rc;
    Parse sParse;
    rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
    if( rc==SQLITE_OK ){
      if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
        NameContext sNC;
        memset(&sNC, 0, sizeof(sNC));
        sNC.pParse = &sParse;
        sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC);
        if( sParse.nErr ) rc = sParse.rc;







|







106365
106366
106367
106368
106369
106370
106371
106372
106373
106374
106375
106376
106377
106378
106379
  db->xAuth = 0;
#endif

  UNUSED_PARAMETER(NotUsed);
  if( zDb && zInput ){
    int rc;
    Parse sParse;
    rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
    if( rc==SQLITE_OK ){
      if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
        NameContext sNC;
        memset(&sNC, 0, sizeof(sNC));
        sNC.pParse = &sParse;
        sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC);
        if( sParse.nErr ) rc = sParse.rc;
105510
105511
105512
105513
105514
105515
105516
105517
105518
105519
105520
105521
105522
105523
105524
105525
105526
105527
105528
105529
105530
105531
105532
105533
105534

105535
105536
105537
105538



105539
105540
105541
105542
105543
105544
105545
105546
105547
105548
105549
105550
105551
105552
105553
105554
105555
105556
105557
105558
105559
105560
105561
105562
105563
105564
105565
105566
105567
105568
105569
105570
105571
105572
105573
105574
105575
105576
105577
105578
105579
105580
105581
105582
105583
105584
105585
105586
105587
105588
105589
105590
105591
105592
105593
105594
105595
105596
105597
105598
105599
105600
105601
105602
105603
105604
105605
105606
105607
105608
105609
105610
105611
105612
105613
105614
105615
105616
105617
105618
105619
105620
105621
#endif

/*
** Three SQL functions - stat_init(), stat_push(), and stat_get() -
** share an instance of the following structure to hold their state
** information.
*/
typedef struct Stat4Accum Stat4Accum;
typedef struct Stat4Sample Stat4Sample;
struct Stat4Sample {
  tRowcnt *anEq;                  /* sqlite_stat4.nEq */
  tRowcnt *anDLt;                 /* sqlite_stat4.nDLt */
#ifdef SQLITE_ENABLE_STAT4
  tRowcnt *anLt;                  /* sqlite_stat4.nLt */
  union {
    i64 iRowid;                     /* Rowid in main table of the key */
    u8 *aRowid;                     /* Key for WITHOUT ROWID tables */
  } u;
  u32 nRowid;                     /* Sizeof aRowid[] */
  u8 isPSample;                   /* True if a periodic sample */
  int iCol;                       /* If !isPSample, the reason for inclusion */
  u32 iHash;                      /* Tiebreaker hash */
#endif
};                                                    
struct Stat4Accum {

  tRowcnt nRow;             /* Number of rows in the entire table */
  tRowcnt nPSample;         /* How often to do a periodic sample */
  int nCol;                 /* Number of columns in index + pk/rowid */
  int nKeyCol;              /* Number of index columns w/o the pk/rowid */



  int mxSample;             /* Maximum number of samples to accumulate */
  Stat4Sample current;      /* Current row as a Stat4Sample */
  u32 iPrn;                 /* Pseudo-random number used for sampling */
  Stat4Sample *aBest;       /* Array of nCol best samples */
  int iMin;                 /* Index in a[] of entry with minimum score */
  int nSample;              /* Current number of samples */
  int nMaxEqZero;           /* Max leading 0 in anEq[] for any a[] entry */
  int iGet;                 /* Index of current sample accessed by stat_get() */
  Stat4Sample *a;           /* Array of mxSample Stat4Sample objects */
  sqlite3 *db;              /* Database connection, for malloc() */
};

/* Reclaim memory used by a Stat4Sample
*/
#ifdef SQLITE_ENABLE_STAT4
static void sampleClear(sqlite3 *db, Stat4Sample *p){
  assert( db!=0 );
  if( p->nRowid ){
    sqlite3DbFree(db, p->u.aRowid);
    p->nRowid = 0;
  }
}
#endif

/* Initialize the BLOB value of a ROWID
*/
#ifdef SQLITE_ENABLE_STAT4
static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
  assert( db!=0 );
  if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
  p->u.aRowid = sqlite3DbMallocRawNN(db, n);
  if( p->u.aRowid ){
    p->nRowid = n;
    memcpy(p->u.aRowid, pData, n);
  }else{
    p->nRowid = 0;
  }
}
#endif

/* Initialize the INTEGER value of a ROWID.
*/
#ifdef SQLITE_ENABLE_STAT4
static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
  assert( db!=0 );
  if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
  p->nRowid = 0;
  p->u.iRowid = iRowid;
}
#endif


/*
** Copy the contents of object (*pFrom) into (*pTo).
*/
#ifdef SQLITE_ENABLE_STAT4
static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
  pTo->isPSample = pFrom->isPSample;
  pTo->iCol = pFrom->iCol;
  pTo->iHash = pFrom->iHash;
  memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol);
  memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol);
  memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol);
  if( pFrom->nRowid ){
    sampleSetRowid(p->db, pTo, pFrom->nRowid, pFrom->u.aRowid);
  }else{
    sampleSetRowidInt64(p->db, pTo, pFrom->u.iRowid);
  }
}
#endif

/*
** Reclaim all memory of a Stat4Accum structure.
*/
static void stat4Destructor(void *pOld){
  Stat4Accum *p = (Stat4Accum*)pOld;
#ifdef SQLITE_ENABLE_STAT4
  int i;
  for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
  for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
  sampleClear(p->db, &p->current);
#endif
  sqlite3DbFree(p->db, p);







|
|
|














|
>

<


>
>
>

<

|




|
|


|


|











|















|












|















|

|
|







106671
106672
106673
106674
106675
106676
106677
106678
106679
106680
106681
106682
106683
106684
106685
106686
106687
106688
106689
106690
106691
106692
106693
106694
106695
106696
106697

106698
106699
106700
106701
106702
106703

106704
106705
106706
106707
106708
106709
106710
106711
106712
106713
106714
106715
106716
106717
106718
106719
106720
106721
106722
106723
106724
106725
106726
106727
106728
106729
106730
106731
106732
106733
106734
106735
106736
106737
106738
106739
106740
106741
106742
106743
106744
106745
106746
106747
106748
106749
106750
106751
106752
106753
106754
106755
106756
106757
106758
106759
106760
106761
106762
106763
106764
106765
106766
106767
106768
106769
106770
106771
106772
106773
106774
106775
106776
106777
106778
106779
106780
106781
106782
106783
106784
#endif

/*
** Three SQL functions - stat_init(), stat_push(), and stat_get() -
** share an instance of the following structure to hold their state
** information.
*/
typedef struct StatAccum StatAccum;
typedef struct StatSample StatSample;
struct StatSample {
  tRowcnt *anEq;                  /* sqlite_stat4.nEq */
  tRowcnt *anDLt;                 /* sqlite_stat4.nDLt */
#ifdef SQLITE_ENABLE_STAT4
  tRowcnt *anLt;                  /* sqlite_stat4.nLt */
  union {
    i64 iRowid;                     /* Rowid in main table of the key */
    u8 *aRowid;                     /* Key for WITHOUT ROWID tables */
  } u;
  u32 nRowid;                     /* Sizeof aRowid[] */
  u8 isPSample;                   /* True if a periodic sample */
  int iCol;                       /* If !isPSample, the reason for inclusion */
  u32 iHash;                      /* Tiebreaker hash */
#endif
};                                                    
struct StatAccum {
  sqlite3 *db;              /* Database connection, for malloc() */
  tRowcnt nRow;             /* Number of rows in the entire table */

  int nCol;                 /* Number of columns in index + pk/rowid */
  int nKeyCol;              /* Number of index columns w/o the pk/rowid */
  StatSample current;       /* Current row as a StatSample */
#ifdef SQLITE_ENABLE_STAT4
  tRowcnt nPSample;         /* How often to do a periodic sample */
  int mxSample;             /* Maximum number of samples to accumulate */

  u32 iPrn;                 /* Pseudo-random number used for sampling */
  StatSample *aBest;        /* Array of nCol best samples */
  int iMin;                 /* Index in a[] of entry with minimum score */
  int nSample;              /* Current number of samples */
  int nMaxEqZero;           /* Max leading 0 in anEq[] for any a[] entry */
  int iGet;                 /* Index of current sample accessed by stat_get() */
  StatSample *a;            /* Array of mxSample StatSample objects */
#endif
};

/* Reclaim memory used by a StatSample
*/
#ifdef SQLITE_ENABLE_STAT4
static void sampleClear(sqlite3 *db, StatSample *p){
  assert( db!=0 );
  if( p->nRowid ){
    sqlite3DbFree(db, p->u.aRowid);
    p->nRowid = 0;
  }
}
#endif

/* Initialize the BLOB value of a ROWID
*/
#ifdef SQLITE_ENABLE_STAT4
static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){
  assert( db!=0 );
  if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
  p->u.aRowid = sqlite3DbMallocRawNN(db, n);
  if( p->u.aRowid ){
    p->nRowid = n;
    memcpy(p->u.aRowid, pData, n);
  }else{
    p->nRowid = 0;
  }
}
#endif

/* Initialize the INTEGER value of a ROWID.
*/
#ifdef SQLITE_ENABLE_STAT4
static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){
  assert( db!=0 );
  if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
  p->nRowid = 0;
  p->u.iRowid = iRowid;
}
#endif


/*
** Copy the contents of object (*pFrom) into (*pTo).
*/
#ifdef SQLITE_ENABLE_STAT4
static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
  pTo->isPSample = pFrom->isPSample;
  pTo->iCol = pFrom->iCol;
  pTo->iHash = pFrom->iHash;
  memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol);
  memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol);
  memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol);
  if( pFrom->nRowid ){
    sampleSetRowid(p->db, pTo, pFrom->nRowid, pFrom->u.aRowid);
  }else{
    sampleSetRowidInt64(p->db, pTo, pFrom->u.iRowid);
  }
}
#endif

/*
** Reclaim all memory of a StatAccum structure.
*/
static void statAccumDestructor(void *pOld){
  StatAccum *p = (StatAccum*)pOld;
#ifdef SQLITE_ENABLE_STAT4
  int i;
  for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
  for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
  sampleClear(p->db, &p->current);
#endif
  sqlite3DbFree(p->db, p);
105635
105636
105637
105638
105639
105640
105641
105642
105643
105644
105645
105646
105647
105648
105649
105650
105651
105652
105653
105654
105655
105656
105657
105658
105659
105660
105661
105662
105663
105664
105665
105666
105667
105668
105669
105670
105671
105672
105673
105674
105675
105676
105677
105678
105679
105680
105681
105682
105683
105684
** Note 2:  C is only used for STAT4.
**
** For indexes on ordinary rowid tables, N==K+1.  But for indexes on
** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
** PRIMARY KEY of the table.  The covering index that implements the
** original WITHOUT ROWID table as N==K as a special case.
**
** This routine allocates the Stat4Accum object in heap memory. The return 
** value is a pointer to the Stat4Accum object.  The datatype of the
** return value is BLOB, but it is really just a pointer to the Stat4Accum
** object.
*/
static void statInit(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  Stat4Accum *p;
  int nCol;                       /* Number of columns in index being sampled */
  int nKeyCol;                    /* Number of key columns */
  int nColUp;                     /* nCol rounded up for alignment */
  int n;                          /* Bytes of space to allocate */
  sqlite3 *db;                    /* Database connection */
#ifdef SQLITE_ENABLE_STAT4
  int mxSample = SQLITE_STAT4_SAMPLES;
#endif

  /* Decode the three function arguments */
  UNUSED_PARAMETER(argc);
  nCol = sqlite3_value_int(argv[0]);
  assert( nCol>0 );
  nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol;
  nKeyCol = sqlite3_value_int(argv[1]);
  assert( nKeyCol<=nCol );
  assert( nKeyCol>0 );

  /* Allocate the space required for the Stat4Accum object */
  n = sizeof(*p) 
    + sizeof(tRowcnt)*nColUp                  /* Stat4Accum.anEq */
    + sizeof(tRowcnt)*nColUp                  /* Stat4Accum.anDLt */
#ifdef SQLITE_ENABLE_STAT4
    + sizeof(tRowcnt)*nColUp                  /* Stat4Accum.anLt */
    + sizeof(Stat4Sample)*(nCol+mxSample)     /* Stat4Accum.aBest[], a[] */
    + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
#endif
  ;
  db = sqlite3_context_db_handle(context);
  p = sqlite3DbMallocZero(db, n);
  if( p==0 ){
    sqlite3_result_error_nomem(context);







|
|
|







|


















|

|
|

|
|







106798
106799
106800
106801
106802
106803
106804
106805
106806
106807
106808
106809
106810
106811
106812
106813
106814
106815
106816
106817
106818
106819
106820
106821
106822
106823
106824
106825
106826
106827
106828
106829
106830
106831
106832
106833
106834
106835
106836
106837
106838
106839
106840
106841
106842
106843
106844
106845
106846
106847
** Note 2:  C is only used for STAT4.
**
** For indexes on ordinary rowid tables, N==K+1.  But for indexes on
** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
** PRIMARY KEY of the table.  The covering index that implements the
** original WITHOUT ROWID table as N==K as a special case.
**
** This routine allocates the StatAccum object in heap memory. The return 
** value is a pointer to the StatAccum object.  The datatype of the
** return value is BLOB, but it is really just a pointer to the StatAccum
** object.
*/
static void statInit(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  StatAccum *p;
  int nCol;                       /* Number of columns in index being sampled */
  int nKeyCol;                    /* Number of key columns */
  int nColUp;                     /* nCol rounded up for alignment */
  int n;                          /* Bytes of space to allocate */
  sqlite3 *db;                    /* Database connection */
#ifdef SQLITE_ENABLE_STAT4
  int mxSample = SQLITE_STAT4_SAMPLES;
#endif

  /* Decode the three function arguments */
  UNUSED_PARAMETER(argc);
  nCol = sqlite3_value_int(argv[0]);
  assert( nCol>0 );
  nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol;
  nKeyCol = sqlite3_value_int(argv[1]);
  assert( nKeyCol<=nCol );
  assert( nKeyCol>0 );

  /* Allocate the space required for the StatAccum object */
  n = sizeof(*p) 
    + sizeof(tRowcnt)*nColUp                  /* StatAccum.anEq */
    + sizeof(tRowcnt)*nColUp                  /* StatAccum.anDLt */
#ifdef SQLITE_ENABLE_STAT4
    + sizeof(tRowcnt)*nColUp                  /* StatAccum.anLt */
    + sizeof(StatSample)*(nCol+mxSample)      /* StatAccum.aBest[], a[] */
    + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
#endif
  ;
  db = sqlite3_context_db_handle(context);
  p = sqlite3DbMallocZero(db, n);
  if( p==0 ){
    sqlite3_result_error_nomem(context);
105699
105700
105701
105702
105703
105704
105705
105706
105707
105708
105709
105710
105711
105712
105713
105714
105715
105716
105717
105718
105719
105720
105721
105722
105723
105724
105725
105726
105727
105728
105729
105730
105731
105732
105733
105734

    p->iGet = -1;
    p->mxSample = mxSample;
    p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
    p->current.anLt = &p->current.anEq[nColUp];
    p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
  
    /* Set up the Stat4Accum.a[] and aBest[] arrays */
    p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
    p->aBest = &p->a[mxSample];
    pSpace = (u8*)(&p->a[mxSample+nCol]);
    for(i=0; i<(mxSample+nCol); i++){
      p->a[i].anEq = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
      p->a[i].anLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
      p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
    }
    assert( (pSpace - (u8*)p)==n );
  
    for(i=0; i<nCol; i++){
      p->aBest[i].iCol = i;
    }
  }
#endif

  /* Return a pointer to the allocated object to the caller.  Note that
  ** only the pointer (the 2nd parameter) matters.  The size of the object
  ** (given by the 3rd parameter) is never used and can be any positive
  ** value. */
  sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
}
static const FuncDef statInitFuncdef = {
  2+IsStat4,       /* nArg */
  SQLITE_UTF8,     /* funcFlags */
  0,               /* pUserData */
  0,               /* pNext */
  statInit,        /* xSFunc */







|
|



















|







106862
106863
106864
106865
106866
106867
106868
106869
106870
106871
106872
106873
106874
106875
106876
106877
106878
106879
106880
106881
106882
106883
106884
106885
106886
106887
106888
106889
106890
106891
106892
106893
106894
106895
106896
106897

    p->iGet = -1;
    p->mxSample = mxSample;
    p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
    p->current.anLt = &p->current.anEq[nColUp];
    p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
  
    /* Set up the StatAccum.a[] and aBest[] arrays */
    p->a = (struct StatSample*)&p->current.anLt[nColUp];
    p->aBest = &p->a[mxSample];
    pSpace = (u8*)(&p->a[mxSample+nCol]);
    for(i=0; i<(mxSample+nCol); i++){
      p->a[i].anEq = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
      p->a[i].anLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
      p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
    }
    assert( (pSpace - (u8*)p)==n );
  
    for(i=0; i<nCol; i++){
      p->aBest[i].iCol = i;
    }
  }
#endif

  /* Return a pointer to the allocated object to the caller.  Note that
  ** only the pointer (the 2nd parameter) matters.  The size of the object
  ** (given by the 3rd parameter) is never used and can be any positive
  ** value. */
  sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
}
static const FuncDef statInitFuncdef = {
  2+IsStat4,       /* nArg */
  SQLITE_UTF8,     /* funcFlags */
  0,               /* pUserData */
  0,               /* pNext */
  statInit,        /* xSFunc */
105747
105748
105749
105750
105751
105752
105753
105754
105755
105756
105757
105758
105759
105760
105761
105762
105763
** In other words, if we assume that the cardinalities of the selected
** column for pNew and pOld are equal, is pNew to be preferred over pOld.
**
** This function assumes that for each argument sample, the contents of
** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. 
*/
static int sampleIsBetterPost(
  Stat4Accum *pAccum, 
  Stat4Sample *pNew, 
  Stat4Sample *pOld
){
  int nCol = pAccum->nCol;
  int i;
  assert( pNew->iCol==pOld->iCol );
  for(i=pNew->iCol+1; i<nCol; i++){
    if( pNew->anEq[i]>pOld->anEq[i] ) return 1;
    if( pNew->anEq[i]<pOld->anEq[i] ) return 0;







|
|
|







106910
106911
106912
106913
106914
106915
106916
106917
106918
106919
106920
106921
106922
106923
106924
106925
106926
** In other words, if we assume that the cardinalities of the selected
** column for pNew and pOld are equal, is pNew to be preferred over pOld.
**
** This function assumes that for each argument sample, the contents of
** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. 
*/
static int sampleIsBetterPost(
  StatAccum *pAccum, 
  StatSample *pNew, 
  StatSample *pOld
){
  int nCol = pAccum->nCol;
  int i;
  assert( pNew->iCol==pOld->iCol );
  for(i=pNew->iCol+1; i<nCol; i++){
    if( pNew->anEq[i]>pOld->anEq[i] ) return 1;
    if( pNew->anEq[i]<pOld->anEq[i] ) return 0;
105771
105772
105773
105774
105775
105776
105777
105778
105779
105780
105781
105782
105783
105784
105785
105786
105787
105788
105789
105790
105791
105792
105793
105794
105795
105796
105797
105798
105799
105800
105801
105802
105803
105804
105805
105806
105807
105808
105809
105810
105811
105812
105813
105814
105815
105816
105817
105818
105819
105820
105821
105822
105823
105824
105825
105826
105827
105828
105829
105830
105831
105832
105833
105834
105835
105836
105837
105838
105839
105840
105841
105842
105843
105844
105845
105846
105847
105848
105849
/*
** Return true if pNew is to be preferred over pOld.
**
** This function assumes that for each argument sample, the contents of
** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid. 
*/
static int sampleIsBetter(
  Stat4Accum *pAccum, 
  Stat4Sample *pNew, 
  Stat4Sample *pOld
){
  tRowcnt nEqNew = pNew->anEq[pNew->iCol];
  tRowcnt nEqOld = pOld->anEq[pOld->iCol];

  assert( pOld->isPSample==0 && pNew->isPSample==0 );
  assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) );

  if( (nEqNew>nEqOld) ) return 1;
  if( nEqNew==nEqOld ){
    if( pNew->iCol<pOld->iCol ) return 1;
    return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld));
  }
  return 0;
}

/*
** Copy the contents of sample *pNew into the p->a[] array. If necessary,
** remove the least desirable sample from p->a[] to make room.
*/
static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
  Stat4Sample *pSample = 0;
  int i;

  assert( IsStat4 || nEqZero==0 );

  /* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
  ** values in the anEq[] array of any sample in Stat4Accum.a[]. In
  ** other words, if nMaxEqZero is n, then it is guaranteed that there
  ** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */
  if( nEqZero>p->nMaxEqZero ){
    p->nMaxEqZero = nEqZero;
  }
  if( pNew->isPSample==0 ){
    Stat4Sample *pUpgrade = 0;
    assert( pNew->anEq[pNew->iCol]>0 );

    /* This sample is being added because the prefix that ends in column 
    ** iCol occurs many times in the table. However, if we have already
    ** added a sample that shares this prefix, there is no need to add
    ** this one. Instead, upgrade the priority of the highest priority
    ** existing sample that shares this prefix.  */
    for(i=p->nSample-1; i>=0; i--){
      Stat4Sample *pOld = &p->a[i];
      if( pOld->anEq[pNew->iCol]==0 ){
        if( pOld->isPSample ) return;
        assert( pOld->iCol>pNew->iCol );
        assert( sampleIsBetter(p, pNew, pOld) );
        if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){
          pUpgrade = pOld;
        }
      }
    }
    if( pUpgrade ){
      pUpgrade->iCol = pNew->iCol;
      pUpgrade->anEq[pUpgrade->iCol] = pNew->anEq[pUpgrade->iCol];
      goto find_new_min;
    }
  }

  /* If necessary, remove sample iMin to make room for the new sample. */
  if( p->nSample>=p->mxSample ){
    Stat4Sample *pMin = &p->a[p->iMin];
    tRowcnt *anEq = pMin->anEq;
    tRowcnt *anLt = pMin->anLt;
    tRowcnt *anDLt = pMin->anDLt;
    sampleClear(p->db, pMin);
    memmove(pMin, &pMin[1], sizeof(p->a[0])*(p->nSample-p->iMin-1));
    pSample = &p->a[p->nSample-1];
    pSample->nRowid = 0;







|
|
|



















|
|




|
|

|




|








|


















|







106934
106935
106936
106937
106938
106939
106940
106941
106942
106943
106944
106945
106946
106947
106948
106949
106950
106951
106952
106953
106954
106955
106956
106957
106958
106959
106960
106961
106962
106963
106964
106965
106966
106967
106968
106969
106970
106971
106972
106973
106974
106975
106976
106977
106978
106979
106980
106981
106982
106983
106984
106985
106986
106987
106988
106989
106990
106991
106992
106993
106994
106995
106996
106997
106998
106999
107000
107001
107002
107003
107004
107005
107006
107007
107008
107009
107010
107011
107012
/*
** Return true if pNew is to be preferred over pOld.
**
** This function assumes that for each argument sample, the contents of
** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid. 
*/
static int sampleIsBetter(
  StatAccum *pAccum, 
  StatSample *pNew, 
  StatSample *pOld
){
  tRowcnt nEqNew = pNew->anEq[pNew->iCol];
  tRowcnt nEqOld = pOld->anEq[pOld->iCol];

  assert( pOld->isPSample==0 && pNew->isPSample==0 );
  assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) );

  if( (nEqNew>nEqOld) ) return 1;
  if( nEqNew==nEqOld ){
    if( pNew->iCol<pOld->iCol ) return 1;
    return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld));
  }
  return 0;
}

/*
** Copy the contents of sample *pNew into the p->a[] array. If necessary,
** remove the least desirable sample from p->a[] to make room.
*/
static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){
  StatSample *pSample = 0;
  int i;

  assert( IsStat4 || nEqZero==0 );

  /* StatAccum.nMaxEqZero is set to the maximum number of leading 0
  ** values in the anEq[] array of any sample in StatAccum.a[]. In
  ** other words, if nMaxEqZero is n, then it is guaranteed that there
  ** are no samples with StatSample.anEq[m]==0 for (m>=n). */
  if( nEqZero>p->nMaxEqZero ){
    p->nMaxEqZero = nEqZero;
  }
  if( pNew->isPSample==0 ){
    StatSample *pUpgrade = 0;
    assert( pNew->anEq[pNew->iCol]>0 );

    /* This sample is being added because the prefix that ends in column 
    ** iCol occurs many times in the table. However, if we have already
    ** added a sample that shares this prefix, there is no need to add
    ** this one. Instead, upgrade the priority of the highest priority
    ** existing sample that shares this prefix.  */
    for(i=p->nSample-1; i>=0; i--){
      StatSample *pOld = &p->a[i];
      if( pOld->anEq[pNew->iCol]==0 ){
        if( pOld->isPSample ) return;
        assert( pOld->iCol>pNew->iCol );
        assert( sampleIsBetter(p, pNew, pOld) );
        if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){
          pUpgrade = pOld;
        }
      }
    }
    if( pUpgrade ){
      pUpgrade->iCol = pNew->iCol;
      pUpgrade->anEq[pUpgrade->iCol] = pNew->anEq[pUpgrade->iCol];
      goto find_new_min;
    }
  }

  /* If necessary, remove sample iMin to make room for the new sample. */
  if( p->nSample>=p->mxSample ){
    StatSample *pMin = &p->a[p->iMin];
    tRowcnt *anEq = pMin->anEq;
    tRowcnt *anLt = pMin->anLt;
    tRowcnt *anDLt = pMin->anDLt;
    sampleClear(p->db, pMin);
    memmove(pMin, &pMin[1], sizeof(p->a[0])*(p->nSample-p->iMin-1));
    pSample = &p->a[p->nSample-1];
    pSample->nRowid = 0;
105878
105879
105880
105881
105882
105883
105884

105885
105886
105887
105888
105889
105890
105891
105892
105893
105894
105895
105896
105897
105898
105899
105900
105901
105902
105903
105904
105905
    }
    assert( iMin>=0 );
    p->iMin = iMin;
  }
}
#endif /* SQLITE_ENABLE_STAT4 */


/*
** Field iChng of the index being scanned has changed. So at this point
** p->current contains a sample that reflects the previous row of the
** index. The value of anEq[iChng] and subsequent anEq[] elements are
** correct at this point.
*/
static void samplePushPrevious(Stat4Accum *p, int iChng){
#ifdef SQLITE_ENABLE_STAT4
  int i;

  /* Check if any samples from the aBest[] array should be pushed
  ** into IndexSample.a[] at this point.  */
  for(i=(p->nCol-2); i>=iChng; i--){
    Stat4Sample *pBest = &p->aBest[i];
    pBest->anEq[i] = p->current.anEq[i];
    if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
      sampleInsert(p, pBest, i);
    }
  }

  /* Check that no sample contains an anEq[] entry with an index of







>






|
<





|







107041
107042
107043
107044
107045
107046
107047
107048
107049
107050
107051
107052
107053
107054
107055

107056
107057
107058
107059
107060
107061
107062
107063
107064
107065
107066
107067
107068
    }
    assert( iMin>=0 );
    p->iMin = iMin;
  }
}
#endif /* SQLITE_ENABLE_STAT4 */

#ifdef SQLITE_ENABLE_STAT4
/*
** Field iChng of the index being scanned has changed. So at this point
** p->current contains a sample that reflects the previous row of the
** index. The value of anEq[iChng] and subsequent anEq[] elements are
** correct at this point.
*/
static void samplePushPrevious(StatAccum *p, int iChng){

  int i;

  /* Check if any samples from the aBest[] array should be pushed
  ** into IndexSample.a[] at this point.  */
  for(i=(p->nCol-2); i>=iChng; i--){
    StatSample *pBest = &p->aBest[i];
    pBest->anEq[i] = p->current.anEq[i];
    if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
      sampleInsert(p, pBest, i);
    }
  }

  /* Check that no sample contains an anEq[] entry with an index of
105915
105916
105917
105918
105919
105920
105921
105922
105923
105924
105925
105926
105927
105928
105929
105930
105931
105932
105933
105934
105935
105936
105937
105938
105939
105940
105941
105942
105943
105944
105945
105946
105947
105948
105949
105950
105951
105952
105953
105954
105955
105956
105957
105958
105959
105960
105961
105962
105963
105964
105965
105966

105967

105968
105969
105970
105971
105972
105973
105974
      int j;
      for(j=iChng; j<p->nCol; j++){
        if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
      }
    }
    p->nMaxEqZero = iChng;
  }
#endif

#ifndef SQLITE_ENABLE_STAT4
  UNUSED_PARAMETER( p );
  UNUSED_PARAMETER( iChng );
#endif
}

/*
** Implementation of the stat_push SQL function:  stat_push(P,C,R)
** Arguments:
**
**    P     Pointer to the Stat4Accum object created by stat_init()
**    C     Index of left-most column to differ from previous row
**    R     Rowid for the current row.  Might be a key record for
**          WITHOUT ROWID tables.
**
** This SQL function always returns NULL.  It's purpose it to accumulate
** statistical data and/or samples in the Stat4Accum object about the
** index being analyzed.  The stat_get() SQL function will later be used to
** extract relevant information for constructing the sqlite_statN tables.
**
** The R parameter is only used for STAT4
*/
static void statPush(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int i;

  /* The three function arguments */
  Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
  int iChng = sqlite3_value_int(argv[1]);

  UNUSED_PARAMETER( argc );
  UNUSED_PARAMETER( context );
  assert( p->nCol>0 );
  assert( iChng<p->nCol );

  if( p->nRow==0 ){
    /* This is the first call to this function. Do initialization. */
    for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
  }else{
    /* Second and subsequent calls get processed here */

    samplePushPrevious(p, iChng);


    /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
    ** to the current row of the index. */
    for(i=0; i<iChng; i++){
      p->current.anEq[i]++;
    }
    for(i=iChng; i<p->nCol; i++){







<
|
|
<
<
<
<





|





|













|












>

>







107078
107079
107080
107081
107082
107083
107084

107085
107086




107087
107088
107089
107090
107091
107092
107093
107094
107095
107096
107097
107098
107099
107100
107101
107102
107103
107104
107105
107106
107107
107108
107109
107110
107111
107112
107113
107114
107115
107116
107117
107118
107119
107120
107121
107122
107123
107124
107125
107126
107127
107128
107129
107130
107131
107132
107133
107134
      int j;
      for(j=iChng; j<p->nCol; j++){
        if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
      }
    }
    p->nMaxEqZero = iChng;
  }

}
#endif /* SQLITE_ENABLE_STAT4 */





/*
** Implementation of the stat_push SQL function:  stat_push(P,C,R)
** Arguments:
**
**    P     Pointer to the StatAccum object created by stat_init()
**    C     Index of left-most column to differ from previous row
**    R     Rowid for the current row.  Might be a key record for
**          WITHOUT ROWID tables.
**
** This SQL function always returns NULL.  It's purpose it to accumulate
** statistical data and/or samples in the StatAccum object about the
** index being analyzed.  The stat_get() SQL function will later be used to
** extract relevant information for constructing the sqlite_statN tables.
**
** The R parameter is only used for STAT4
*/
static void statPush(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int i;

  /* The three function arguments */
  StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
  int iChng = sqlite3_value_int(argv[1]);

  UNUSED_PARAMETER( argc );
  UNUSED_PARAMETER( context );
  assert( p->nCol>0 );
  assert( iChng<p->nCol );

  if( p->nRow==0 ){
    /* This is the first call to this function. Do initialization. */
    for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
  }else{
    /* Second and subsequent calls get processed here */
#ifdef SQLITE_ENABLE_STAT4
    samplePushPrevious(p, iChng);
#endif

    /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
    ** to the current row of the index. */
    for(i=0; i<iChng; i++){
      p->current.anEq[i]++;
    }
    for(i=iChng; i<p->nCol; i++){
106029
106030
106031
106032
106033
106034
106035
106036
106037
106038
106039
106040
106041
106042
106043
106044
106045
106046
106047
106048
106049
106050
106051
106052
106053
106054
106055
106056
106057
106058
106059
106060
106061
106062
106063
106064
106065
106066
106067
106068
106069
106070
106071
106072
106073
106074
106075
106076
106077
106078
106079
106080
106081
106082
106083
106084
106085
#define STAT_GET_NEQ   2          /* "neq" column of stat[34] entry */
#define STAT_GET_NLT   3          /* "nlt" column of stat[34] entry */
#define STAT_GET_NDLT  4          /* "ndlt" column of stat[34] entry */

/*
** Implementation of the stat_get(P,J) SQL function.  This routine is
** used to query statistical information that has been gathered into
** the Stat4Accum object by prior calls to stat_push().  The P parameter
** has type BLOB but it is really just a pointer to the Stat4Accum object.
** The content to returned is determined by the parameter J
** which is one of the STAT_GET_xxxx values defined above.
**
** The stat_get(P,J) function is not available to generic SQL.  It is
** inserted as part of a manually constructed bytecode program.  (See
** the callStatGet() routine below.)  It is guaranteed that the P
** parameter will always be a poiner to a Stat4Accum object, never a
** NULL.
**
** If STAT4 is not enabled, then J is always
** STAT_GET_STAT1 and is hence omitted and this routine becomes
** a one-parameter function, stat_get(P), that always returns the
** stat1 table entry information.
*/
static void statGet(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
#ifdef SQLITE_ENABLE_STAT4
  /* STAT4 has a parameter on this routine. */
  int eCall = sqlite3_value_int(argv[1]);
  assert( argc==2 );
  assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ 
       || eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT
       || eCall==STAT_GET_NDLT 
  );
  if( eCall==STAT_GET_STAT1 )
#else
  assert( argc==1 );
#endif
  {
    /* Return the value to store in the "stat" column of the sqlite_stat1
    ** table for this index.
    **
    ** The value is a string composed of a list of integers describing 
    ** the index. The first integer in the list is the total number of 
    ** entries in the index. There is one additional integer in the list 
    ** for each indexed column. This additional integer is an estimate of
    ** the number of rows matched by a stabbing query on the index using
    ** a key with the corresponding number of fields. In other words,
    ** if the index is on columns (a,b) and the sqlite_stat1 value is 
    ** "100 10 2", then SQLite estimates that:
    **
    **   * the index contains 100 rows,
    **   * "WHERE a=?" matches 10 rows, and
    **   * "WHERE a=? AND b=?" matches 2 rows.







|
|






|












|




















|







107189
107190
107191
107192
107193
107194
107195
107196
107197
107198
107199
107200
107201
107202
107203
107204
107205
107206
107207
107208
107209
107210
107211
107212
107213
107214
107215
107216
107217
107218
107219
107220
107221
107222
107223
107224
107225
107226
107227
107228
107229
107230
107231
107232
107233
107234
107235
107236
107237
107238
107239
107240
107241
107242
107243
107244
107245
#define STAT_GET_NEQ   2          /* "neq" column of stat[34] entry */
#define STAT_GET_NLT   3          /* "nlt" column of stat[34] entry */
#define STAT_GET_NDLT  4          /* "ndlt" column of stat[34] entry */

/*
** Implementation of the stat_get(P,J) SQL function.  This routine is
** used to query statistical information that has been gathered into
** the StatAccum object by prior calls to stat_push().  The P parameter
** has type BLOB but it is really just a pointer to the StatAccum object.
** The content to returned is determined by the parameter J
** which is one of the STAT_GET_xxxx values defined above.
**
** The stat_get(P,J) function is not available to generic SQL.  It is
** inserted as part of a manually constructed bytecode program.  (See
** the callStatGet() routine below.)  It is guaranteed that the P
** parameter will always be a pointer to a StatAccum object, never a
** NULL.
**
** If STAT4 is not enabled, then J is always
** STAT_GET_STAT1 and is hence omitted and this routine becomes
** a one-parameter function, stat_get(P), that always returns the
** stat1 table entry information.
*/
static void statGet(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
#ifdef SQLITE_ENABLE_STAT4
  /* STAT4 has a parameter on this routine. */
  int eCall = sqlite3_value_int(argv[1]);
  assert( argc==2 );
  assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ 
       || eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT
       || eCall==STAT_GET_NDLT 
  );
  if( eCall==STAT_GET_STAT1 )
#else
  assert( argc==1 );
#endif
  {
    /* Return the value to store in the "stat" column of the sqlite_stat1
    ** table for this index.
    **
    ** The value is a string composed of a list of integers describing 
    ** the index. The first integer in the list is the total number of 
    ** entries in the index. There is one additional integer in the list 
    ** for each indexed column. This additional integer is an estimate of
    ** the number of rows matched by a equality query on the index using
    ** a key with the corresponding number of fields. In other words,
    ** if the index is on columns (a,b) and the sqlite_stat1 value is 
    ** "100 10 2", then SQLite estimates that:
    **
    **   * the index contains 100 rows,
    **   * "WHERE a=?" matches 10 rows, and
    **   * "WHERE a=? AND b=?" matches 2 rows.
106114
106115
106116
106117
106118
106119
106120
106121
106122
106123
106124
106125
106126
106127
106128
#ifdef SQLITE_ENABLE_STAT4
  else if( eCall==STAT_GET_ROWID ){
    if( p->iGet<0 ){
      samplePushPrevious(p, 0);
      p->iGet = 0;
    }
    if( p->iGet<p->nSample ){
      Stat4Sample *pS = p->a + p->iGet;
      if( pS->nRowid==0 ){
        sqlite3_result_int64(context, pS->u.iRowid);
      }else{
        sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid,
                            SQLITE_TRANSIENT);
      }
    }







|







107274
107275
107276
107277
107278
107279
107280
107281
107282
107283
107284
107285
107286
107287
107288
#ifdef SQLITE_ENABLE_STAT4
  else if( eCall==STAT_GET_ROWID ){
    if( p->iGet<0 ){
      samplePushPrevious(p, 0);
      p->iGet = 0;
    }
    if( p->iGet<p->nSample ){
      StatSample *pS = p->a + p->iGet;
      if( pS->nRowid==0 ){
        sqlite3_result_int64(context, pS->u.iRowid);
      }else{
        sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid,
                            SQLITE_TRANSIENT);
      }
    }
106205
106206
106207
106208
106209
106210
106211
106212
106213
106214
106215
106216
106217
106218
106219
  int iTabCur;                 /* Table cursor */
  Vdbe *v;                     /* The virtual machine being built up */
  int i;                       /* Loop counter */
  int jZeroRows = -1;          /* Jump from here if number of rows is zero */
  int iDb;                     /* Index of database containing pTab */
  u8 needTableCnt = 1;         /* True to count the table */
  int regNewRowid = iMem++;    /* Rowid for the inserted record */
  int regStat4 = iMem++;       /* Register to hold Stat4Accum object */
  int regChng = iMem++;        /* Index of changed index field */
#ifdef SQLITE_ENABLE_STAT4
  int regRowid = iMem++;       /* Rowid argument passed to stat_push() */
#endif
  int regTemp = iMem++;        /* Temporary use register */
  int regTabname = iMem++;     /* Register containing table name */
  int regIdxname = iMem++;     /* Register containing index name */







|







107365
107366
107367
107368
107369
107370
107371
107372
107373
107374
107375
107376
107377
107378
107379
  int iTabCur;                 /* Table cursor */
  Vdbe *v;                     /* The virtual machine being built up */
  int i;                       /* Loop counter */
  int jZeroRows = -1;          /* Jump from here if number of rows is zero */
  int iDb;                     /* Index of database containing pTab */
  u8 needTableCnt = 1;         /* True to count the table */
  int regNewRowid = iMem++;    /* Rowid for the inserted record */
  int regStat4 = iMem++;       /* Register to hold StatAccum object */
  int regChng = iMem++;        /* Index of changed index field */
#ifdef SQLITE_ENABLE_STAT4
  int regRowid = iMem++;       /* Rowid argument passed to stat_push() */
#endif
  int regTemp = iMem++;        /* Temporary use register */
  int regTabname = iMem++;     /* Register containing table name */
  int regIdxname = iMem++;     /* Register containing index name */
107173
107174
107175
107176
107177
107178
107179











107180
107181
107182
107183
107184
107185
107186
      rc = sqlite3ResolveExprNames(pName, pExpr);
    }else{
      pExpr->op = TK_STRING;
    }
  }
  return rc;
}












/*
** An SQL user-function registered to do the work of an ATTACH statement. The
** three arguments to the function come directly from an attach statement:
**
**     ATTACH DATABASE x AS y KEY z
**







>
>
>
>
>
>
>
>
>
>
>







108333
108334
108335
108336
108337
108338
108339
108340
108341
108342
108343
108344
108345
108346
108347
108348
108349
108350
108351
108352
108353
108354
108355
108356
108357
      rc = sqlite3ResolveExprNames(pName, pExpr);
    }else{
      pExpr->op = TK_STRING;
    }
  }
  return rc;
}

/*
** Return true if zName points to a name that may be used to refer to
** database iDb attached to handle db.
*/
SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){
  return (
      sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0
   || (iDb==0 && sqlite3StrICmp("main", zName)==0)
  );
}

/*
** An SQL user-function registered to do the work of an ATTACH statement. The
** three arguments to the function come directly from an attach statement:
**
**     ATTACH DATABASE x AS y KEY z
**
107246
107247
107248
107249
107250
107251
107252
107253
107254
107255
107256
107257
107258
107259
107260
107261
107262
    if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
      zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", 
        db->aLimit[SQLITE_LIMIT_ATTACHED]
      );
      goto attach_error;
    }
    for(i=0; i<db->nDb; i++){
      char *z = db->aDb[i].zDbSName;
      assert( z && zName );
      if( sqlite3StrICmp(z, zName)==0 ){
        zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
        goto attach_error;
      }
    }
  
    /* Allocate the new entry in the db->aDb[] array and initialize the schema
    ** hash tables.







<
|
|







108417
108418
108419
108420
108421
108422
108423

108424
108425
108426
108427
108428
108429
108430
108431
108432
    if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
      zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", 
        db->aLimit[SQLITE_LIMIT_ATTACHED]
      );
      goto attach_error;
    }
    for(i=0; i<db->nDb; i++){

      assert( zName );
      if( sqlite3DbIsNamed(db, i, zName) ){
        zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
        goto attach_error;
      }
    }
  
    /* Allocate the new entry in the db->aDb[] array and initialize the schema
    ** hash tables.
107316
107317
107318
107319
107320
107321
107322
107323
107324
107325
107326
107327
107328
107329
107330
107331
107332
107333
107334
107335
107336
107337
107338
107339
107340
107341
107342
107343
107344
107345
107346
107347
107348
107349
107350
107351
107352
107353
107354
107355
107356
107357
107358
107359
107360
107361
107362
107363
107364
107365
107366
#endif
    sqlite3BtreeLeave(pNew->pBt);
  }
  pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
  if( rc==SQLITE_OK && pNew->zDbSName==0 ){
    rc = SQLITE_NOMEM_BKPT;
  }


#ifdef SQLITE_HAS_CODEC
  if( rc==SQLITE_OK ){
    extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
    extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
    int nKey;
    char *zKey;
    int t = sqlite3_value_type(argv[2]);
    switch( t ){
      case SQLITE_INTEGER:
      case SQLITE_FLOAT:
        zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
        rc = SQLITE_ERROR;
        break;
        
      case SQLITE_TEXT:
      case SQLITE_BLOB:
        nKey = sqlite3_value_bytes(argv[2]);
        zKey = (char *)sqlite3_value_blob(argv[2]);
        rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
        break;

      case SQLITE_NULL:
        /* No key specified.  Use the key from URI filename, or if none,
        ** use the key from the main database. */
        if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){
          sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
          if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
            rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
          }
        }
        break;
    }
  }
#endif
  sqlite3_free( zPath );

  /* If the file was opened successfully, read the schema for the new database.
  ** If this fails, or if opening the file failed, then close the file and 
  ** remove the entry from the db->aDb[] array. i.e. put everything back the
  ** way we found it.
  */
  if( rc==SQLITE_OK ){







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







108486
108487
108488
108489
108490
108491
108492




































108493
108494
108495
108496
108497
108498
108499
108500
#endif
    sqlite3BtreeLeave(pNew->pBt);
  }
  pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
  if( rc==SQLITE_OK && pNew->zDbSName==0 ){
    rc = SQLITE_NOMEM_BKPT;
  }




































  sqlite3_free_filename( zPath );

  /* If the file was opened successfully, read the schema for the new database.
  ** If this fails, or if opening the file failed, then close the file and 
  ** remove the entry from the db->aDb[] array. i.e. put everything back the
  ** way we found it.
  */
  if( rc==SQLITE_OK ){
107437
107438
107439
107440
107441
107442
107443
107444
107445
107446
107447
107448
107449
107450
107451

  UNUSED_PARAMETER(NotUsed);

  if( zName==0 ) zName = "";
  for(i=0; i<db->nDb; i++){
    pDb = &db->aDb[i];
    if( pDb->pBt==0 ) continue;
    if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
  }

  if( i>=db->nDb ){
    sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName);
    goto detach_error;
  }
  if( i<2 ){







|







108571
108572
108573
108574
108575
108576
108577
108578
108579
108580
108581
108582
108583
108584
108585

  UNUSED_PARAMETER(NotUsed);

  if( zName==0 ) zName = "";
  for(i=0; i<db->nDb; i++){
    pDb = &db->aDb[i];
    if( pDb->pBt==0 ) continue;
    if( sqlite3DbIsNamed(db, i, zName) ) break;
  }

  if( i>=db->nDb ){
    sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName);
    goto detach_error;
  }
  if( i<2 ){
107606
107607
107608
107609
107610
107611
107612
107613
107614
107615
107616
107617
107618
107619
107620
  db = pParse->db;
  assert( db->nDb>iDb );
  pFix->pParse = pParse;
  pFix->zDb = db->aDb[iDb].zDbSName;
  pFix->pSchema = db->aDb[iDb].pSchema;
  pFix->zType = zType;
  pFix->pName = pName;
  pFix->bVarOnly = (iDb==1);
}

/*
** The following set of routines walk through the parse tree and assign
** a specific database to all table references where the database name
** was left unspecified in the original SQL statement.  The pFix structure
** must have been initialized by a prior call to sqlite3FixInit().







|







108740
108741
108742
108743
108744
108745
108746
108747
108748
108749
108750
108751
108752
108753
108754
  db = pParse->db;
  assert( db->nDb>iDb );
  pFix->pParse = pParse;
  pFix->zDb = db->aDb[iDb].zDbSName;
  pFix->pSchema = db->aDb[iDb].pSchema;
  pFix->zType = zType;
  pFix->pName = pName;
  pFix->bTemp = (iDb==1);
}

/*
** The following set of routines walk through the parse tree and assign
** a specific database to all table references where the database name
** was left unspecified in the original SQL statement.  The pFix structure
** must have been initialized by a prior call to sqlite3FixInit().
107628
107629
107630
107631
107632
107633
107634
107635
107636


107637
107638
107639
107640
107641
107642
107643
107644
107645
107646
107647
107648
107649
107650

107651
107652
107653
107654
107655
107656
107657
** checks out, these routines return 0.
*/
SQLITE_PRIVATE int sqlite3FixSrcList(
  DbFixer *pFix,       /* Context of the fixation */
  SrcList *pList       /* The Source list to check and modify */
){
  int i;
  const char *zDb;
  struct SrcList_item *pItem;



  if( NEVER(pList==0) ) return 0;
  zDb = pFix->zDb;
  for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
    if( pFix->bVarOnly==0 ){
      if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
        sqlite3ErrorMsg(pFix->pParse,
            "%s %T cannot reference objects in database %s",
            pFix->zType, pFix->pName, pItem->zDatabase);
        return 1;
      }
      sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
      pItem->zDatabase = 0;
      pItem->pSchema = pFix->pSchema;

    }
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
    if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
    if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
#endif
    if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){
      return 1;







<

>
>


|

|
|





|


>







108762
108763
108764
108765
108766
108767
108768

108769
108770
108771
108772
108773
108774
108775
108776
108777
108778
108779
108780
108781
108782
108783
108784
108785
108786
108787
108788
108789
108790
108791
108792
108793
** checks out, these routines return 0.
*/
SQLITE_PRIVATE int sqlite3FixSrcList(
  DbFixer *pFix,       /* Context of the fixation */
  SrcList *pList       /* The Source list to check and modify */
){
  int i;

  struct SrcList_item *pItem;
  sqlite3 *db = pFix->pParse->db;
  int iDb = sqlite3FindDbName(db, pFix->zDb);

  if( NEVER(pList==0) ) return 0;

  for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
    if( pFix->bTemp==0 ){
      if( pItem->zDatabase && iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
        sqlite3ErrorMsg(pFix->pParse,
            "%s %T cannot reference objects in database %s",
            pFix->zType, pFix->pName, pItem->zDatabase);
        return 1;
      }
      sqlite3DbFree(db, pItem->zDatabase);
      pItem->zDatabase = 0;
      pItem->pSchema = pFix->pSchema;
      pItem->fg.fromDDL = 1;
    }
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
    if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
    if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
#endif
    if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){
      return 1;
107699
107700
107701
107702
107703
107704
107705
107706
107707
107708
107709
107710
107711
107712
107713
  return 0;
}
SQLITE_PRIVATE int sqlite3FixExpr(
  DbFixer *pFix,     /* Context of the fixation */
  Expr *pExpr        /* The expression to be fixed to one database */
){
  while( pExpr ){
    ExprSetProperty(pExpr, EP_Indirect);
    if( pExpr->op==TK_VARIABLE ){
      if( pFix->pParse->db->init.busy ){
        pExpr->op = TK_NULL;
      }else{
        sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
        return 1;
      }







|







108835
108836
108837
108838
108839
108840
108841
108842
108843
108844
108845
108846
108847
108848
108849
  return 0;
}
SQLITE_PRIVATE int sqlite3FixExpr(
  DbFixer *pFix,     /* Context of the fixation */
  Expr *pExpr        /* The expression to be fixed to one database */
){
  while( pExpr ){
    if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
    if( pExpr->op==TK_VARIABLE ){
      if( pFix->pParse->db->init.busy ){
        pExpr->op = TK_NULL;
      }else{
        sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
        return 1;
      }
108365
108366
108367
108368
108369
108370
108371
108372
108373
108374
108375
108376
108377
108378
108379
  if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
    return 0;
  }
#endif
  while(1){
    for(i=OMIT_TEMPDB; i<db->nDb; i++){
      int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
      if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
        assert( sqlite3SchemaMutexHeld(db, j, 0) );
        p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
        if( p ) return p;
      }
    }
    /* Not found.  If the name we were looking for was temp.sqlite_master
    ** then change the name to sqlite_temp_master and try again. */







|







109501
109502
109503
109504
109505
109506
109507
109508
109509
109510
109511
109512
109513
109514
109515
  if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
    return 0;
  }
#endif
  while(1){
    for(i=OMIT_TEMPDB; i<db->nDb; i++){
      int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
      if( zDatabase==0 || sqlite3DbIsNamed(db, j, zDatabase) ){
        assert( sqlite3SchemaMutexHeld(db, j, 0) );
        p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
        if( p ) return p;
      }
    }
    /* Not found.  If the name we were looking for was temp.sqlite_master
    ** then change the name to sqlite_temp_master and try again. */
108487
108488
108489
108490
108491
108492
108493
108494
108495
108496
108497
108498
108499
108500
108501
  int i;
  /* All mutexes are required for schema access.  Make sure we hold them. */
  assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
  for(i=OMIT_TEMPDB; i<db->nDb; i++){
    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    Schema *pSchema = db->aDb[j].pSchema;
    assert( pSchema );
    if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue;
    assert( sqlite3SchemaMutexHeld(db, j, 0) );
    p = sqlite3HashFind(&pSchema->idxHash, zName);
    if( p ) break;
  }
  return p;
}








|







109623
109624
109625
109626
109627
109628
109629
109630
109631
109632
109633
109634
109635
109636
109637
  int i;
  /* All mutexes are required for schema access.  Make sure we hold them. */
  assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
  for(i=OMIT_TEMPDB; i<db->nDb; i++){
    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    Schema *pSchema = db->aDb[j].pSchema;
    assert( pSchema );
    if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
    assert( sqlite3SchemaMutexHeld(db, j, 0) );
    p = sqlite3HashFind(&pSchema->idxHash, zName);
    if( p ) break;
  }
  return p;
}

108640
108641
108642
108643
108644
108645
108646

108647
108648
108649
108650
108651
108652
108653
*/
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
  int i;
  Column *pCol;
  assert( pTable!=0 );
  if( (pCol = pTable->aCol)!=0 ){
    for(i=0; i<pTable->nCol; i++, pCol++){

      sqlite3DbFree(db, pCol->zName);
      sqlite3ExprDelete(db, pCol->pDflt);
      sqlite3DbFree(db, pCol->zColl);
    }
    sqlite3DbFree(db, pTable->aCol);
  }
}







>







109776
109777
109778
109779
109780
109781
109782
109783
109784
109785
109786
109787
109788
109789
109790
*/
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
  int i;
  Column *pCol;
  assert( pTable!=0 );
  if( (pCol = pTable->aCol)!=0 ){
    for(i=0; i<pTable->nCol; i++, pCol++){
      assert( pCol->zName==0 || pCol->hName==sqlite3StrIHash(pCol->zName) );
      sqlite3DbFree(db, pCol->zName);
      sqlite3ExprDelete(db, pCol->pDflt);
      sqlite3DbFree(db, pCol->zColl);
    }
    sqlite3DbFree(db, pTable->aCol);
  }
}
108997
108998
108999
109000
109001
109002
109003
109004


109005
109006
109007
109008
109009
109010
109011
109012
109013
109014
109015
109016
109017
**    INPUTS:     0 1 2 3 4 5 6 7 8
**    OUTPUTS:    0 1 6 2 3 7 4 5 8
**
** So, in other words, this routine shifts all the virtual columns to
** the end.
**
** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and
** this routine is a no-op macro.


*/
SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){
  int i;
  i16 n;
  assert( iCol<pTab->nCol );
  if( (pTab->tabFlags & TF_HasVirtual)==0 ) return iCol;
  for(i=0, n=0; i<iCol; i++){
    if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++;
  }
  if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){
    /* iCol is a virtual column itself */
    return pTab->nNVCol + i - n;
  }else{







|
>
>





|







110134
110135
110136
110137
110138
110139
110140
110141
110142
110143
110144
110145
110146
110147
110148
110149
110150
110151
110152
110153
110154
110155
110156
**    INPUTS:     0 1 2 3 4 5 6 7 8
**    OUTPUTS:    0 1 6 2 3 7 4 5 8
**
** So, in other words, this routine shifts all the virtual columns to
** the end.
**
** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and
** this routine is a no-op macro.  If the pTab does not have any virtual
** columns, then this routine is no-op that always return iCol.  If iCol
** is negative (indicating the ROWID column) then this routine return iCol.
*/
SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){
  int i;
  i16 n;
  assert( iCol<pTab->nCol );
  if( (pTab->tabFlags & TF_HasVirtual)==0 || iCol<0 ) return iCol;
  for(i=0, n=0; i<iCol; i++){
    if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++;
  }
  if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){
    /* iCol is a virtual column itself */
    return pTab->nNVCol + i - n;
  }else{
109286
109287
109288
109289
109290
109291
109292

109293
109294
109295
109296
109297
109298
109299
      return;
    }
    p->aCol = aNew;
  }
  pCol = &p->aCol[p->nCol];
  memset(pCol, 0, sizeof(p->aCol[0]));
  pCol->zName = z;

  sqlite3ColumnPropertiesFromName(p, pCol);
 
  if( pType->n==0 ){
    /* If there is no type specified, columns have the default affinity
    ** 'BLOB' with a default size of 4 bytes. */
    pCol->affinity = SQLITE_AFF_BLOB;
    pCol->szEst = 1;







>







110425
110426
110427
110428
110429
110430
110431
110432
110433
110434
110435
110436
110437
110438
110439
      return;
    }
    p->aCol = aNew;
  }
  pCol = &p->aCol[p->nCol];
  memset(pCol, 0, sizeof(p->aCol[0]));
  pCol->zName = z;
  pCol->hName = sqlite3StrIHash(z);
  sqlite3ColumnPropertiesFromName(p, pCol);
 
  if( pType->n==0 ){
    /* If there is no type specified, columns have the default affinity
    ** 'BLOB' with a default size of 4 bytes. */
    pCol->affinity = SQLITE_AFF_BLOB;
    pCol->szEst = 1;
109452
109453
109454
109455
109456
109457
109458

109459
109460
109461
109462
109463
109464
109465
109466
109467
  const char *zEnd         /* First character past end of defaut value text */
){
  Table *p;
  Column *pCol;
  sqlite3 *db = pParse->db;
  p = pParse->pNewTable;
  if( p!=0 ){

    pCol = &(p->aCol[p->nCol-1]);
    if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){
      sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
          pCol->zName);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
    }else if( pCol->colFlags & COLFLAG_GENERATED ){
      testcase( pCol->colFlags & COLFLAG_VIRTUAL );
      testcase( pCol->colFlags & COLFLAG_STORED );
      sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column");







>

|







110592
110593
110594
110595
110596
110597
110598
110599
110600
110601
110602
110603
110604
110605
110606
110607
110608
  const char *zEnd         /* First character past end of defaut value text */
){
  Table *p;
  Column *pCol;
  sqlite3 *db = pParse->db;
  p = pParse->pNewTable;
  if( p!=0 ){
    int isInit = db->init.busy && db->init.iDb!=1;
    pCol = &(p->aCol[p->nCol-1]);
    if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){
      sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
          pCol->zName);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
    }else if( pCol->colFlags & COLFLAG_GENERATED ){
      testcase( pCol->colFlags & COLFLAG_VIRTUAL );
      testcase( pCol->colFlags & COLFLAG_STORED );
      sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column");
109595
109596
109597
109598
109599
109600
109601

109602
109603
109604
109605
109606
109607
109608
      sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr);
    }
    pTab->iPKey = iCol;
    pTab->keyConf = (u8)onError;
    assert( autoInc==0 || autoInc==1 );
    pTab->tabFlags |= autoInc*TF_Autoincrement;
    if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;

  }else if( autoInc ){
#ifndef SQLITE_OMIT_AUTOINCREMENT
    sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
       "INTEGER PRIMARY KEY");
#endif
  }else{
    sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,







>







110736
110737
110738
110739
110740
110741
110742
110743
110744
110745
110746
110747
110748
110749
110750
      sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr);
    }
    pTab->iPKey = iCol;
    pTab->keyConf = (u8)onError;
    assert( autoInc==0 || autoInc==1 );
    pTab->tabFlags |= autoInc*TF_Autoincrement;
    if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
    (void)sqlite3HasExplicitNulls(pParse, pList);
  }else if( autoInc ){
#ifndef SQLITE_OMIT_AUTOINCREMENT
    sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
       "INTEGER PRIMARY KEY");
#endif
  }else{
    sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
109679
109680
109681
109682
109683
109684
109685


109686

109687
109688
109689
109690
109691
109692
109693
** column.
*/
SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
  u8 eType = COLFLAG_VIRTUAL;
  Table *pTab = pParse->pNewTable;
  Column *pCol;


  if( NEVER(pTab==0) ) goto generated_done;

  pCol = &(pTab->aCol[pTab->nCol-1]);
  if( IN_DECLARE_VTAB ){
    sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns");
    goto generated_done;
  }
  if( pCol->pDflt ) goto generated_error;
  if( pType ){







>
>
|
>







110821
110822
110823
110824
110825
110826
110827
110828
110829
110830
110831
110832
110833
110834
110835
110836
110837
110838
** column.
*/
SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
  u8 eType = COLFLAG_VIRTUAL;
  Table *pTab = pParse->pNewTable;
  Column *pCol;
  if( pTab==0 ){
    /* generated column in an CREATE TABLE IF NOT EXISTS that already exists */
    goto generated_done;
  }
  pCol = &(pTab->aCol[pTab->nCol-1]);
  if( IN_DECLARE_VTAB ){
    sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns");
    goto generated_done;
  }
  if( pCol->pDflt ) goto generated_error;
  if( pType ){
110199
110200
110201
110202
110203
110204
110205


























110206
110207
110208
110209
110210
110211
110212
  pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
  if( pMod==0 ) return 0;
  if( pMod->pModule->iVersion<3 ) return 0;
  if( pMod->pModule->xShadowName==0 ) return 0;
  return pMod->pModule->xShadowName(zTail+1);
}
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */



























/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
**
** The table structure that other action routines have been building
** is added to the internal hash tables, assuming no errors have







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







111344
111345
111346
111347
111348
111349
111350
111351
111352
111353
111354
111355
111356
111357
111358
111359
111360
111361
111362
111363
111364
111365
111366
111367
111368
111369
111370
111371
111372
111373
111374
111375
111376
111377
111378
111379
111380
111381
111382
111383
  pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
  if( pMod==0 ) return 0;
  if( pMod->pModule->iVersion<3 ) return 0;
  if( pMod->pModule->xShadowName==0 ) return 0;
  return pMod->pModule->xShadowName(zTail+1);
}
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */

#ifdef SQLITE_DEBUG
/*
** Mark all nodes of an expression as EP_Immutable, indicating that
** they should not be changed.  Expressions attached to a table or
** index definition are tagged this way to help ensure that we do
** not pass them into code generator routines by mistake.
*/
static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){
  ExprSetVVAProperty(pExpr, EP_Immutable);
  return WRC_Continue;
}
static void markExprListImmutable(ExprList *pList){
  if( pList ){
    Walker w;
    memset(&w, 0, sizeof(w));
    w.xExprCallback = markImmutableExprStep;
    w.xSelectCallback = sqlite3SelectWalkNoop;
    w.xSelectCallback2 = 0;
    sqlite3WalkExprList(&w, pList);
  }
}
#else
#define markExprListImmutable(X)  /* no-op */
#endif /* SQLITE_DEBUG */


/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
**
** The table structure that other action routines have been building
** is added to the internal hash tables, assuming no errors have
110287
110288
110289
110290
110291
110292
110293








110294
110295
110296
110297
110298
110299
110300
110301
110302
110303

110304
110305
110306







110307

110308
110309
110310
110311
110312
110313
110314
  iDb = sqlite3SchemaToIndex(db, p->pSchema);

#ifndef SQLITE_OMIT_CHECK
  /* Resolve names in all CHECK constraint expressions.
  */
  if( p->pCheck ){
    sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);








  }
#endif /* !defined(SQLITE_OMIT_CHECK) */
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
  if( p->tabFlags & TF_HasGenerated ){
    int ii, nNG = 0;
    testcase( p->tabFlags & TF_HasVirtual );
    testcase( p->tabFlags & TF_HasStored );
    for(ii=0; ii<p->nCol; ii++){
      u32 colFlags = p->aCol[ii].colFlags;
      if( (colFlags & COLFLAG_GENERATED)!=0 ){

        testcase( colFlags & COLFLAG_VIRTUAL );
        testcase( colFlags & COLFLAG_STORED );
        sqlite3ResolveSelfReference(pParse, p, NC_GenCol, 







                                    p->aCol[ii].pDflt, 0);

      }else{
        nNG++;
      }
    }
    if( nNG==0 ){
      sqlite3ErrorMsg(pParse, "must have at least one non-generated column");
      return;







>
>
>
>
>
>
>
>










>


|
>
>
>
>
>
>
>
|
>







111458
111459
111460
111461
111462
111463
111464
111465
111466
111467
111468
111469
111470
111471
111472
111473
111474
111475
111476
111477
111478
111479
111480
111481
111482
111483
111484
111485
111486
111487
111488
111489
111490
111491
111492
111493
111494
111495
111496
111497
111498
111499
111500
111501
111502
  iDb = sqlite3SchemaToIndex(db, p->pSchema);

#ifndef SQLITE_OMIT_CHECK
  /* Resolve names in all CHECK constraint expressions.
  */
  if( p->pCheck ){
    sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
    if( pParse->nErr ){
      /* If errors are seen, delete the CHECK constraints now, else they might
      ** actually be used if PRAGMA writable_schema=ON is set. */
      sqlite3ExprListDelete(db, p->pCheck);
      p->pCheck = 0;
    }else{
      markExprListImmutable(p->pCheck);
    }
  }
#endif /* !defined(SQLITE_OMIT_CHECK) */
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
  if( p->tabFlags & TF_HasGenerated ){
    int ii, nNG = 0;
    testcase( p->tabFlags & TF_HasVirtual );
    testcase( p->tabFlags & TF_HasStored );
    for(ii=0; ii<p->nCol; ii++){
      u32 colFlags = p->aCol[ii].colFlags;
      if( (colFlags & COLFLAG_GENERATED)!=0 ){
        Expr *pX = p->aCol[ii].pDflt;
        testcase( colFlags & COLFLAG_VIRTUAL );
        testcase( colFlags & COLFLAG_STORED );
        if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){
          /* If there are errors in resolving the expression, change the
          ** expression to a NULL.  This prevents code generators that operate
          ** on the expression from inserting extra parts into the expression
          ** tree that have been allocated from lookaside memory, which is
          ** illegal in a schema and will lead to errors or heap corruption
          ** when the database connection closes. */
          sqlite3ExprDelete(db, pX);
          p->aCol[ii].pDflt = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
        }
      }else{
        nNG++;
      }
    }
    if( nNG==0 ){
      sqlite3ErrorMsg(pParse, "must have at least one non-generated column");
      return;
110530
110531
110532
110533
110534
110535
110536

110537
110538
110539
110540
110541
110542
110543
  if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail;

  /* Make a copy of the entire SELECT statement that defines the view.
  ** This will force all the Expr.token.z values to be dynamically
  ** allocated rather than point to the input string - which means that
  ** they will persist after the current sqlite3_exec() call returns.
  */

  if( IN_RENAME_OBJECT ){
    p->pSelect = pSelect;
    pSelect = 0;
  }else{
    p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
  }
  p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);







>







111718
111719
111720
111721
111722
111723
111724
111725
111726
111727
111728
111729
111730
111731
111732
  if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail;

  /* Make a copy of the entire SELECT statement that defines the view.
  ** This will force all the Expr.token.z values to be dynamically
  ** allocated rather than point to the input string - which means that
  ** they will persist after the current sqlite3_exec() call returns.
  */
  pSelect->selFlags |= SF_View;
  if( IN_RENAME_OBJECT ){
    p->pSelect = pSelect;
    pSelect = 0;
  }else{
    p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
  }
  p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
110653
110654
110655
110656
110657
110658
110659



110660
110661
110662
110663
110664
110665
110666
110667
110668
110669
110670
110671
110672
110673
110674
110675
110676
110677
110678
110679
110680
110681
110682
110683
110684
110685
110686
110687
110688
110689
110690
110691
110692
110693
110694
110695
    db->xAuth = 0;
    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
    db->xAuth = xAuth;
#else
    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
#endif
    pParse->nTab = n;



    if( pTable->pCheck ){
      /* CREATE VIEW name(arglist) AS ...
      ** The names of the columns in the table are taken from
      ** arglist which is stored in pTable->pCheck.  The pCheck field
      ** normally holds CHECK constraints on an ordinary table, but for
      ** a VIEW it holds the list of column names.
      */
      sqlite3ColumnsFromExprList(pParse, pTable->pCheck, 
                                 &pTable->nCol, &pTable->aCol);
      if( db->mallocFailed==0 
       && pParse->nErr==0
       && pTable->nCol==pSel->pEList->nExpr
      ){
        sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
                                               SQLITE_AFF_NONE);
      }
    }else if( pSelTab ){
      /* CREATE VIEW name AS...  without an argument list.  Construct
      ** the column names from the SELECT statement that defines the view.
      */
      assert( pTable->aCol==0 );
      pTable->nCol = pSelTab->nCol;
      pTable->aCol = pSelTab->aCol;
      pSelTab->nCol = 0;
      pSelTab->aCol = 0;
      assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
    }else{
      pTable->nCol = 0;
      nErr++;
    }
    pTable->nNVCol = pTable->nCol;
    sqlite3DeleteTable(db, pSelTab);
    sqlite3SelectDelete(db, pSel);
    EnableLookaside;
#ifndef SQLITE_OMIT_ALTERTABLE
    pParse->eParseMode = eParseMode;







>
>
>
|















|









<
<
<







111842
111843
111844
111845
111846
111847
111848
111849
111850
111851
111852
111853
111854
111855
111856
111857
111858
111859
111860
111861
111862
111863
111864
111865
111866
111867
111868
111869
111870
111871
111872
111873
111874
111875
111876
111877



111878
111879
111880
111881
111882
111883
111884
    db->xAuth = 0;
    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
    db->xAuth = xAuth;
#else
    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
#endif
    pParse->nTab = n;
    if( pSelTab==0 ){
      pTable->nCol = 0;
      nErr++;
    }else if( pTable->pCheck ){
      /* CREATE VIEW name(arglist) AS ...
      ** The names of the columns in the table are taken from
      ** arglist which is stored in pTable->pCheck.  The pCheck field
      ** normally holds CHECK constraints on an ordinary table, but for
      ** a VIEW it holds the list of column names.
      */
      sqlite3ColumnsFromExprList(pParse, pTable->pCheck, 
                                 &pTable->nCol, &pTable->aCol);
      if( db->mallocFailed==0 
       && pParse->nErr==0
       && pTable->nCol==pSel->pEList->nExpr
      ){
        sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
                                               SQLITE_AFF_NONE);
      }
    }else{
      /* CREATE VIEW name AS...  without an argument list.  Construct
      ** the column names from the SELECT statement that defines the view.
      */
      assert( pTable->aCol==0 );
      pTable->nCol = pSelTab->nCol;
      pTable->aCol = pSelTab->aCol;
      pSelTab->nCol = 0;
      pSelTab->aCol = 0;
      assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );



    }
    pTable->nNVCol = pTable->nCol;
    sqlite3DeleteTable(db, pSelTab);
    sqlite3SelectDelete(db, pSel);
    EnableLookaside;
#ifndef SQLITE_OMIT_ALTERTABLE
    pParse->eParseMode = eParseMode;
111135
111136
111137
111138
111139
111140
111141
111142
111143
111144
111145
111146
111147
111148
111149
    goto fk_end;
  }else{
    nCol = pFromCol->nExpr;
  }
  nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
  if( pToCol ){
    for(i=0; i<pToCol->nExpr; i++){
      nByte += sqlite3Strlen30(pToCol->a[i].zName) + 1;
    }
  }
  pFKey = sqlite3DbMallocZero(db, nByte );
  if( pFKey==0 ){
    goto fk_end;
  }
  pFKey->pFrom = p;







|







112324
112325
112326
112327
112328
112329
112330
112331
112332
112333
112334
112335
112336
112337
112338
    goto fk_end;
  }else{
    nCol = pFromCol->nExpr;
  }
  nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
  if( pToCol ){
    for(i=0; i<pToCol->nExpr; i++){
      nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1;
    }
  }
  pFKey = sqlite3DbMallocZero(db, nByte );
  if( pFKey==0 ){
    goto fk_end;
  }
  pFKey->pFrom = p;
111160
111161
111162
111163
111164
111165
111166
111167
111168
111169
111170
111171
111172
111173
111174
111175
111176
111177
111178
111179
111180
111181
111182
111183
111184
111185
111186
111187
111188
111189
111190
111191
111192
111193
111194
111195
111196
111197
  pFKey->nCol = nCol;
  if( pFromCol==0 ){
    pFKey->aCol[0].iFrom = p->nCol-1;
  }else{
    for(i=0; i<nCol; i++){
      int j;
      for(j=0; j<p->nCol; j++){
        if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
          pFKey->aCol[i].iFrom = j;
          break;
        }
      }
      if( j>=p->nCol ){
        sqlite3ErrorMsg(pParse, 
          "unknown column \"%s\" in foreign key definition", 
          pFromCol->a[i].zName);
        goto fk_end;
      }
      if( IN_RENAME_OBJECT ){
        sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName);
      }
    }
  }
  if( pToCol ){
    for(i=0; i<nCol; i++){
      int n = sqlite3Strlen30(pToCol->a[i].zName);
      pFKey->aCol[i].zCol = z;
      if( IN_RENAME_OBJECT ){
        sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName);
      }
      memcpy(z, pToCol->a[i].zName, n);
      z[n] = 0;
      z += n+1;
    }
  }
  pFKey->isDeferred = 0;
  pFKey->aAction[0] = (u8)(flags & 0xff);            /* ON DELETE action */
  pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff);    /* ON UPDATE action */







|







|



|





|


|

|







112349
112350
112351
112352
112353
112354
112355
112356
112357
112358
112359
112360
112361
112362
112363
112364
112365
112366
112367
112368
112369
112370
112371
112372
112373
112374
112375
112376
112377
112378
112379
112380
112381
112382
112383
112384
112385
112386
  pFKey->nCol = nCol;
  if( pFromCol==0 ){
    pFKey->aCol[0].iFrom = p->nCol-1;
  }else{
    for(i=0; i<nCol; i++){
      int j;
      for(j=0; j<p->nCol; j++){
        if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zEName)==0 ){
          pFKey->aCol[i].iFrom = j;
          break;
        }
      }
      if( j>=p->nCol ){
        sqlite3ErrorMsg(pParse, 
          "unknown column \"%s\" in foreign key definition", 
          pFromCol->a[i].zEName);
        goto fk_end;
      }
      if( IN_RENAME_OBJECT ){
        sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zEName);
      }
    }
  }
  if( pToCol ){
    for(i=0; i<nCol; i++){
      int n = sqlite3Strlen30(pToCol->a[i].zEName);
      pFKey->aCol[i].zCol = z;
      if( IN_RENAME_OBJECT ){
        sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zEName);
      }
      memcpy(z, pToCol->a[i].zEName, n);
      z[n] = 0;
      z += n+1;
    }
  }
  pFKey->isDeferred = 0;
  pFKey->aAction[0] = (u8)(flags & 0xff);            /* ON DELETE action */
  pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff);    /* ON UPDATE action */
111956
111957
111958
111959
111960
111961
111962
111963
111964
111965
111966
111967
111968
111969
111970
111971
111972
111973
111974
111975
111976
111977
111978
111979
111980
111981
111982
111983
111984
111985
111986
111987
111988
111989
111990
111991
111992
111993















111994
111995
111996
111997
111998
111999
112000
            sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
        sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
      }

      sqlite3VdbeJumpHere(v, pIndex->tnum);
    }
  }

  /* When adding an index to the list of indices for a table, make
  ** sure all indices labeled OE_Replace come after all those labeled
  ** OE_Ignore.  This is necessary for the correct constraint check
  ** processing (in sqlite3GenerateConstraintChecks()) as part of
  ** UPDATE and INSERT statements.  
  */
  if( db->init.busy || pTblName==0 ){
    if( onError!=OE_Replace || pTab->pIndex==0
         || pTab->pIndex->onError==OE_Replace){
      pIndex->pNext = pTab->pIndex;
      pTab->pIndex = pIndex;
    }else{
      Index *pOther = pTab->pIndex;
      while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
        pOther = pOther->pNext;
      }
      pIndex->pNext = pOther->pNext;
      pOther->pNext = pIndex;
    }
    pIndex = 0;
  }
  else if( IN_RENAME_OBJECT ){
    assert( pParse->pNewIndex==0 );
    pParse->pNewIndex = pIndex;
    pIndex = 0;
  }

  /* Clean up before exiting */
exit_create_index:
  if( pIndex ) sqlite3FreeIndex(db, pIndex);















  sqlite3ExprDelete(db, pPIWhere);
  sqlite3ExprListDelete(db, pList);
  sqlite3SrcListDelete(db, pTblName);
  sqlite3DbFree(db, zName);
}

/*







<
<
<
<
<
<
<

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











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







113145
113146
113147
113148
113149
113150
113151







113152


113153
113154








113155
113156
113157
113158
113159
113160
113161
113162
113163
113164
113165
113166
113167
113168
113169
113170
113171
113172
113173
113174
113175
113176
113177
113178
113179
113180
113181
113182
113183
113184
113185
113186
113187
            sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
        sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
      }

      sqlite3VdbeJumpHere(v, pIndex->tnum);
    }
  }







  if( db->init.busy || pTblName==0 ){


    pIndex->pNext = pTab->pIndex;
    pTab->pIndex = pIndex;








    pIndex = 0;
  }
  else if( IN_RENAME_OBJECT ){
    assert( pParse->pNewIndex==0 );
    pParse->pNewIndex = pIndex;
    pIndex = 0;
  }

  /* Clean up before exiting */
exit_create_index:
  if( pIndex ) sqlite3FreeIndex(db, pIndex);
  if( pTab ){  /* Ensure all REPLACE indexes are at the end of the list */
    Index **ppFrom = &pTab->pIndex;
    Index *pThis;
    for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
      Index *pNext;
      if( pThis->onError!=OE_Replace ) continue;
      while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){
        *ppFrom = pNext;
        pThis->pNext = pNext->pNext;
        pNext->pNext = pThis;
        ppFrom = &pNext->pNext;
      }
      break;
    }
  }
  sqlite3ExprDelete(db, pPIWhere);
  sqlite3ExprListDelete(db, pList);
  sqlite3SrcListDelete(db, pTblName);
  sqlite3DbFree(db, zName);
}

/*
113219
113220
113221
113222
113223
113224
113225


113226
113227

113228
113229
113230
113231
113232
113233
113234
113235













113236
113237
113238
113239
113240
113241
113242
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
  sqlite3 *db,          /* Database connection to search */
  u8 enc,               /* Desired text encoding */
  const char *zName,    /* Name of the collating sequence.  Might be NULL */
  int create            /* True to create CollSeq if doesn't already exist */
){
  CollSeq *pColl;


  if( zName ){
    pColl = findCollSeqEntry(db, zName, create);

  }else{
    pColl = db->pDfltColl;
  }
  assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
  assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
  if( pColl ) pColl += enc-1;
  return pColl;
}














/*
** This function is responsible for invoking the collation factory callback
** or substituting a collation sequence of a different encoding when the
** requested collation sequence is not available in the desired encoding.
** 
** If it is not NULL, then pColl must point to the database native encoding 







>
>


>



<
<
<


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







114406
114407
114408
114409
114410
114411
114412
114413
114414
114415
114416
114417
114418
114419
114420



114421
114422
114423
114424
114425
114426
114427
114428
114429
114430
114431
114432
114433
114434
114435
114436
114437
114438
114439
114440
114441
114442
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
  sqlite3 *db,          /* Database connection to search */
  u8 enc,               /* Desired text encoding */
  const char *zName,    /* Name of the collating sequence.  Might be NULL */
  int create            /* True to create CollSeq if doesn't already exist */
){
  CollSeq *pColl;
  assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
  assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
  if( zName ){
    pColl = findCollSeqEntry(db, zName, create);
    if( pColl ) pColl += enc-1;
  }else{
    pColl = db->pDfltColl;
  }



  return pColl;
}

/*
** Change the text encoding for a database connection. This means that
** the pDfltColl must change as well.
*/
SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){
  assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
  db->enc = enc;
  /* EVIDENCE-OF: R-08308-17224 The default collating function for all
  ** strings is BINARY. 
  */
  db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0);
}

/*
** This function is responsible for invoking the collation factory callback
** or substituting a collation sequence of a different encoding when the
** requested collation sequence is not available in the desired encoding.
** 
** If it is not NULL, then pColl must point to the database native encoding 
113344
113345
113346
113347
113348
113349
113350

113351

113352
113353

113354
113355
113356
113357
113358
113359
113360
113361
113362
113363
#define FUNC_PERFECT_MATCH 6  /* The score for a perfect match */
static int matchQuality(
  FuncDef *p,     /* The function we are evaluating for match quality */
  int nArg,       /* Desired number of arguments.  (-1)==any */
  u8 enc          /* Desired text encoding */
){
  int match;



  /* nArg of -2 is a special case */
  if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;


  /* Wrong number of arguments means "no match" */
  if( p->nArg!=nArg && p->nArg>=0 ) return 0;

  /* Give a better score to a function with a specific number of arguments
  ** than to function that accepts any number of arguments. */
  if( p->nArg==nArg ){
    match = 4;
  }else{
    match = 1;







>

>
|
|
>
|
<
<







114544
114545
114546
114547
114548
114549
114550
114551
114552
114553
114554
114555
114556
114557


114558
114559
114560
114561
114562
114563
114564
#define FUNC_PERFECT_MATCH 6  /* The score for a perfect match */
static int matchQuality(
  FuncDef *p,     /* The function we are evaluating for match quality */
  int nArg,       /* Desired number of arguments.  (-1)==any */
  u8 enc          /* Desired text encoding */
){
  int match;
  assert( p->nArg>=-1 );

  /* Wrong number of arguments means "no match" */
  if( p->nArg!=nArg ){
    if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
    if( p->nArg>=0 ) return 0;
  }



  /* Give a better score to a function with a specific number of arguments
  ** than to function that accepts any number of arguments. */
  if( p->nArg==nArg ){
    match = 4;
  }else{
    match = 1;
114114
114115
114116
114117
114118
114119
114120
114121


114122
114123
114124
114125
114126
114127
114128
        iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
      }
      testcase( IsVirtual(pTab) );
      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
                                 iTabCur, aToOpen, &iDataCur, &iIdxCur);
      assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
      assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
      if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);


    }
  
    /* Set up a loop over the rowids/primary-keys that were found in the
    ** where-clause loop above.
    */
    if( eOnePass!=ONEPASS_OFF ){
      assert( nKey==nPk );  /* OP_Found will use an unpacked key */







|
>
>







115315
115316
115317
115318
115319
115320
115321
115322
115323
115324
115325
115326
115327
115328
115329
115330
115331
        iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
      }
      testcase( IsVirtual(pTab) );
      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
                                 iTabCur, aToOpen, &iDataCur, &iIdxCur);
      assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
      assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
      if( eOnePass==ONEPASS_MULTI ){
        sqlite3VdbeJumpHereOrPopInst(v, iAddrOnce);
      }
    }
  
    /* Set up a loop over the rowids/primary-keys that were found in the
    ** where-clause loop above.
    */
    if( eOnePass!=ONEPASS_OFF ){
      assert( nKey==nPk );  /* OP_Found will use an unpacked key */
114563
114564
114565
114566
114567
114568
114569

114570

114571
114572
114573
114574
114575
114576
114577
** This file contains the C-language implementations for many of the SQL
** functions of SQLite.  (Some function, and in particular the date and
** time functions, are implemented separately.)
*/
/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
/* #include <assert.h> */

/* #include <math.h> */

/* #include "vdbeInt.h" */

/*
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
  VdbeOp *pOp;







>

>







115766
115767
115768
115769
115770
115771
115772
115773
115774
115775
115776
115777
115778
115779
115780
115781
115782
** This file contains the C-language implementations for many of the SQL
** functions of SQLite.  (Some function, and in particular the date and
** time functions, are implemented separately.)
*/
/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
/* #include <assert.h> */
#ifndef SQLITE_OMIT_FLOATING_POINT
/* #include <math.h> */
#endif
/* #include "vdbeInt.h" */

/*
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
  VdbeOp *pOp;
115398
115399
115400
115401
115402
115403
115404

115405
115406
115407
115408
115409
115410
115411
  sqlite3_value **argv
){
  const unsigned char *zA, *zB;
  u32 escape;
  int nPat;
  sqlite3 *db = sqlite3_context_db_handle(context);
  struct compareInfo *pInfo = sqlite3_user_data(context);


#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
  if( sqlite3_value_type(argv[0])==SQLITE_BLOB
   || sqlite3_value_type(argv[1])==SQLITE_BLOB
  ){
#ifdef SQLITE_TEST
    sqlite3_like_count++;







>







116603
116604
116605
116606
116607
116608
116609
116610
116611
116612
116613
116614
116615
116616
116617
  sqlite3_value **argv
){
  const unsigned char *zA, *zB;
  u32 escape;
  int nPat;
  sqlite3 *db = sqlite3_context_db_handle(context);
  struct compareInfo *pInfo = sqlite3_user_data(context);
  struct compareInfo backupInfo;

#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
  if( sqlite3_value_type(argv[0])==SQLITE_BLOB
   || sqlite3_value_type(argv[1])==SQLITE_BLOB
  ){
#ifdef SQLITE_TEST
    sqlite3_like_count++;
115433
115434
115435
115436
115437
115438
115439






115440
115441
115442
115443
115444
115445
115446
    if( zEsc==0 ) return;
    if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){
      sqlite3_result_error(context, 
          "ESCAPE expression must be a single character", -1);
      return;
    }
    escape = sqlite3Utf8Read(&zEsc);






  }else{
    escape = pInfo->matchSet;
  }
  zB = sqlite3_value_text(argv[0]);
  zA = sqlite3_value_text(argv[1]);
  if( zA && zB ){
#ifdef SQLITE_TEST







>
>
>
>
>
>







116639
116640
116641
116642
116643
116644
116645
116646
116647
116648
116649
116650
116651
116652
116653
116654
116655
116656
116657
116658
    if( zEsc==0 ) return;
    if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){
      sqlite3_result_error(context, 
          "ESCAPE expression must be a single character", -1);
      return;
    }
    escape = sqlite3Utf8Read(&zEsc);
    if( escape==pInfo->matchAll || escape==pInfo->matchOne ){
      memcpy(&backupInfo, pInfo, sizeof(backupInfo));
      pInfo = &backupInfo;
      if( escape==pInfo->matchAll ) pInfo->matchAll = 0;
      if( escape==pInfo->matchOne ) pInfo->matchOne = 0;
    }
  }else{
    escape = pInfo->matchSet;
  }
  zB = sqlite3_value_text(argv[0]);
  zA = sqlite3_value_text(argv[1]);
  if( zA && zB ){
#ifdef SQLITE_TEST
116409
116410
116411
116412
116413
116414
116415



116416
116417
116418
116419
116420
116421
116422
116423
116424
116425
116426
116427
116428
116429
116430
116431
116432
116433
116434
116435
116436
116437














116438
116439
116440
116441
116442
116443
116444
  int nExpr;
  if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
    return 0;
  }
  assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
  nExpr = pExpr->x.pList->nExpr;
  pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);



  if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
    return 0;
  }
  if( nExpr<3 ){
    aWc[3] = 0;
  }else{
    Expr *pEscape = pExpr->x.pList->a[2].pExpr;
    char *zEscape;
    if( pEscape->op!=TK_STRING ) return 0;
    zEscape = pEscape->u.zToken;
    if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
    aWc[3] = zEscape[0];
  }

  /* The memcpy() statement assumes that the wildcard characters are
  ** the first three statements in the compareInfo structure.  The
  ** asserts() that follow verify that assumption
  */
  memcpy(aWc, pDef->pUserData, 3);
  assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
  assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
  assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );














  *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0;
  return 1;
}

/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table.  This occurs at start-time (as







>
>
>



<
<
<
<
<
<
<
<
<
<









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







117621
117622
117623
117624
117625
117626
117627
117628
117629
117630
117631
117632
117633










117634
117635
117636
117637
117638
117639
117640
117641
117642
117643
117644
117645
117646
117647
117648
117649
117650
117651
117652
117653
117654
117655
117656
117657
117658
117659
117660
117661
117662
117663
  int nExpr;
  if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
    return 0;
  }
  assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
  nExpr = pExpr->x.pList->nExpr;
  pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
  if( pDef==0 ) return 0;
#endif
  if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
    return 0;
  }











  /* The memcpy() statement assumes that the wildcard characters are
  ** the first three statements in the compareInfo structure.  The
  ** asserts() that follow verify that assumption
  */
  memcpy(aWc, pDef->pUserData, 3);
  assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
  assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
  assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );

  if( nExpr<3 ){
    aWc[3] = 0;
  }else{
    Expr *pEscape = pExpr->x.pList->a[2].pExpr;
    char *zEscape;
    if( pEscape->op!=TK_STRING ) return 0;
    zEscape = pEscape->u.zToken;
    if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
    if( zEscape[0]==aWc[0] ) return 0;
    if( zEscape[0]==aWc[1] ) return 0;
    aWc[3] = zEscape[0];
  }

  *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0;
  return 1;
}

/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table.  This occurs at start-time (as
116454
116455
116456
116457
116458
116459
116460








116461
116462
116463
116464
116465
116466
116467
116468
116469
116470
116471
116472
116473
116474
116475
116476
116477
116478
116479
116480
116481
116482
116483
116484
116485
116486
116487
  ** The array cannot be constant since changes are made to the
  ** FuncDef.pHash elements at start-time.  The elements of this array
  ** are read-only after initialization is complete.
  **
  ** For peak efficiency, put the most frequently used function last.
  */
  static FuncDef aBuiltinFunc[] = {








#ifdef SQLITE_SOUNDEX
    FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    VFUNCTION(load_extension,    1, 0, 0, loadExt          ),
    VFUNCTION(load_extension,    2, 0, 0, loadExt          ),
#endif
#if SQLITE_USER_AUTHENTICATION
    FUNCTION(sqlite_crypt,       2, 0, 0, sqlite3CryptFunc ),
#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
    DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    FUNCTION2(unlikely,          1, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
    FUNCTION2(likelihood,        2, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
    FUNCTION2(likely,            1, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
#ifdef SQLITE_DEBUG
    FUNCTION2(affinity,          1, 0, 0, noopFunc,  SQLITE_FUNC_AFFINITY),
#endif
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    FUNCTION2(sqlite_offset,     1, 0, 0, noopFunc,  SQLITE_FUNC_OFFSET|
                                                     SQLITE_FUNC_TYPEOF),
#endif
    FUNCTION(ltrim,              1, 1, 0, trimFunc         ),
    FUNCTION(ltrim,              2, 1, 0, trimFunc         ),
    FUNCTION(rtrim,              1, 2, 0, trimFunc         ),







>
>
>
>
>
>
>
>




|
|








|
|
|
<
<
<







117673
117674
117675
117676
117677
117678
117679
117680
117681
117682
117683
117684
117685
117686
117687
117688
117689
117690
117691
117692
117693
117694
117695
117696
117697
117698
117699
117700
117701
117702
117703
117704



117705
117706
117707
117708
117709
117710
117711
  ** The array cannot be constant since changes are made to the
  ** FuncDef.pHash elements at start-time.  The elements of this array
  ** are read-only after initialization is complete.
  **
  ** For peak efficiency, put the most frequently used function last.
  */
  static FuncDef aBuiltinFunc[] = {
/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/
    TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
    TEST_FUNC(expr_compare,        2, INLINEFUNC_expr_compare,        0),
    TEST_FUNC(expr_implies_expr,   2, INLINEFUNC_expr_implies_expr,   0),
#ifdef SQLITE_DEBUG
    TEST_FUNC(affinity,          1, INLINEFUNC_affinity, 0),
#endif
/***** Regular functions *****/
#ifdef SQLITE_SOUNDEX
    FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    SFUNCTION(load_extension,    1, 0, 0, loadExt          ),
    SFUNCTION(load_extension,    2, 0, 0, loadExt          ),
#endif
#if SQLITE_USER_AUTHENTICATION
    FUNCTION(sqlite_crypt,       2, 0, 0, sqlite3CryptFunc ),
#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
    DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    INLINE_FUNC(unlikely,        1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
    INLINE_FUNC(likelihood,      2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
    INLINE_FUNC(likely,          1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),



#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    FUNCTION2(sqlite_offset,     1, 0, 0, noopFunc,  SQLITE_FUNC_OFFSET|
                                                     SQLITE_FUNC_TYPEOF),
#endif
    FUNCTION(ltrim,              1, 1, 0, trimFunc         ),
    FUNCTION(ltrim,              2, 1, 0, trimFunc         ),
    FUNCTION(rtrim,              1, 2, 0, trimFunc         ),
116506
116507
116508
116509
116510
116511
116512
116513
116514
116515
116516
116517
116518
116519
116520
#ifndef SQLITE_OMIT_FLOATING_POINT
    FUNCTION(round,              1, 0, 0, roundFunc        ),
    FUNCTION(round,              2, 0, 0, roundFunc        ),
#endif
    FUNCTION(upper,              1, 0, 0, upperFunc        ),
    FUNCTION(lower,              1, 0, 0, lowerFunc        ),
    FUNCTION(hex,                1, 0, 0, hexFunc          ),
    FUNCTION2(ifnull,            2, 0, 0, noopFunc,  SQLITE_FUNC_COALESCE),
    VFUNCTION(random,            0, 0, 0, randomFunc       ),
    VFUNCTION(randomblob,        1, 0, 0, randomBlob       ),
    FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
    DFUNCTION(sqlite_version,    0, 0, 0, versionFunc      ),
    DFUNCTION(sqlite_source_id,  0, 0, 0, sourceidFunc     ),
    FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),
    FUNCTION(quote,              1, 0, 0, quoteFunc        ),







|







117730
117731
117732
117733
117734
117735
117736
117737
117738
117739
117740
117741
117742
117743
117744
#ifndef SQLITE_OMIT_FLOATING_POINT
    FUNCTION(round,              1, 0, 0, roundFunc        ),
    FUNCTION(round,              2, 0, 0, roundFunc        ),
#endif
    FUNCTION(upper,              1, 0, 0, upperFunc        ),
    FUNCTION(lower,              1, 0, 0, lowerFunc        ),
    FUNCTION(hex,                1, 0, 0, hexFunc          ),
    INLINE_FUNC(ifnull,          2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
    VFUNCTION(random,            0, 0, 0, randomFunc       ),
    VFUNCTION(randomblob,        1, 0, 0, randomBlob       ),
    FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
    DFUNCTION(sqlite_version,    0, 0, 0, versionFunc      ),
    DFUNCTION(sqlite_source_id,  0, 0, 0, sourceidFunc     ),
    FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),
    FUNCTION(quote,              1, 0, 0, quoteFunc        ),
116546
116547
116548
116549
116550
116551
116552
116553
116554
116555
116556
116557
116558
116559
116560
    LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
#endif
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    FUNCTION(unknown,           -1, 0, 0, unknownFunc      ),
#endif
    FUNCTION(coalesce,           1, 0, 0, 0                ),
    FUNCTION(coalesce,           0, 0, 0, 0                ),
    FUNCTION2(coalesce,         -1, 0, 0, noopFunc,  SQLITE_FUNC_COALESCE),
  };
#ifndef SQLITE_OMIT_ALTERTABLE
  sqlite3AlterFunctions();
#endif
  sqlite3WindowFunctions();
  sqlite3RegisterDateTimeFunctions();
  sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));







|







117770
117771
117772
117773
117774
117775
117776
117777
117778
117779
117780
117781
117782
117783
117784
    LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
#endif
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    FUNCTION(unknown,           -1, 0, 0, unknownFunc      ),
#endif
    FUNCTION(coalesce,           1, 0, 0, 0                ),
    FUNCTION(coalesce,           0, 0, 0, 0                ),
    INLINE_FUNC(coalesce,       -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
  };
#ifndef SQLITE_OMIT_ALTERTABLE
  sqlite3AlterFunctions();
#endif
  sqlite3WindowFunctions();
  sqlite3RegisterDateTimeFunctions();
  sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
117234
117235
117236
117237
117238
117239
117240
117241
117242
117243
117244
117245
117246
117247
117248
      sqlite3WhereEnd(pWInfo);
    }
  }

  /* Clean up the WHERE clause constructed above. */
  sqlite3ExprDelete(db, pWhere);
  if( iFkIfZero ){
    sqlite3VdbeJumpHere(v, iFkIfZero);
  }
}

/*
** This function returns a linked list of FKey objects (connected by
** FKey.pNextTo) holding all children of table pTab.  For example,
** given the following schema:







|







118458
118459
118460
118461
118462
118463
118464
118465
118466
118467
118468
118469
118470
118471
118472
      sqlite3WhereEnd(pWInfo);
    }
  }

  /* Clean up the WHERE clause constructed above. */
  sqlite3ExprDelete(db, pWhere);
  if( iFkIfZero ){
    sqlite3VdbeJumpHereOrPopInst(v, iFkIfZero);
  }
}

/*
** This function returns a linked list of FKey objects (connected by
** FKey.pNextTo) holding all children of table pTab.  For example,
** given the following schema:
118229
118230
118231
118232
118233
118234
118235
118236
118237
118238
118239

118240
118241
118242
118243
118244
118245
118246
    }
#endif
  }
  return 0;
}

/* This walker callback will compute the union of colFlags flags for all
** references columns in a CHECK constraint or generated column expression.
*/
static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){
  if( pExpr->op==TK_COLUMN ){

    pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags;
  }
  return WRC_Continue;
}

#ifndef SQLITE_OMIT_GENERATED_COLUMNS
/*







|


|
>







119453
119454
119455
119456
119457
119458
119459
119460
119461
119462
119463
119464
119465
119466
119467
119468
119469
119470
119471
    }
#endif
  }
  return 0;
}

/* This walker callback will compute the union of colFlags flags for all
** referenced columns in a CHECK constraint or generated column expression.
*/
static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){
  if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 ){
    assert( pExpr->iColumn < pWalker->u.pTab->nCol );
    pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags;
  }
  return WRC_Continue;
}

#ifndef SQLITE_OMIT_GENERATED_COLUMNS
/*
118255
118256
118257
118258
118259
118260
118261






























118262
118263
118264
118265
118266
118267
118268
  int iRegStore,    /* Register holding the first column */
  Table *pTab       /* The table */
){
  int i;
  Walker w;
  Column *pRedo;
  int eProgress;































  /* Because there can be multiple generated columns that refer to one another,
  ** this is a two-pass algorithm.  On the first pass, mark all generated
  ** columns as "not available".
  */
  for(i=0; i<pTab->nCol; i++){
    if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){







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







119480
119481
119482
119483
119484
119485
119486
119487
119488
119489
119490
119491
119492
119493
119494
119495
119496
119497
119498
119499
119500
119501
119502
119503
119504
119505
119506
119507
119508
119509
119510
119511
119512
119513
119514
119515
119516
119517
119518
119519
119520
119521
119522
119523
  int iRegStore,    /* Register holding the first column */
  Table *pTab       /* The table */
){
  int i;
  Walker w;
  Column *pRedo;
  int eProgress;
  VdbeOp *pOp;

  assert( pTab->tabFlags & TF_HasGenerated );
  testcase( pTab->tabFlags & TF_HasVirtual );
  testcase( pTab->tabFlags & TF_HasStored );

  /* Before computing generated columns, first go through and make sure
  ** that appropriate affinity has been applied to the regular columns
  */
  sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
  if( (pTab->tabFlags & TF_HasStored)!=0
   && (pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1))->opcode==OP_Affinity
  ){
    /* Change the OP_Affinity argument to '@' (NONE) for all stored
    ** columns.  '@' is the no-op affinity and those columns have not
    ** yet been computed. */
    int ii, jj;
    char *zP4 = pOp->p4.z;
    assert( zP4!=0 );
    assert( pOp->p4type==P4_DYNAMIC );
    for(ii=jj=0; zP4[jj]; ii++){
      if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){
        continue;
      }
      if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){
        zP4[jj] = SQLITE_AFF_NONE;
      }
      jj++;
    }
  }

  /* Because there can be multiple generated columns that refer to one another,
  ** this is a two-pass algorithm.  On the first pass, mark all generated
  ** columns as "not available".
  */
  for(i=0; i<pTab->nCol; i++){
    if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
118975
118976
118977
118978
118979
118980
118981




118982
118983
118984
118985
118986
118987
118988
#ifndef SQLITE_OMIT_UPSERT
  if( pUpsert ){
    if( IsVirtual(pTab) ){
      sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
              pTab->zName);
      goto insert_cleanup;
    }




    if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){
      goto insert_cleanup;
    }
    pTabList->a[0].iCursor = iDataCur;
    pUpsert->pUpsertSrc = pTabList;
    pUpsert->regData = regData;
    pUpsert->iDataCur = iDataCur;







>
>
>
>







120230
120231
120232
120233
120234
120235
120236
120237
120238
120239
120240
120241
120242
120243
120244
120245
120246
120247
#ifndef SQLITE_OMIT_UPSERT
  if( pUpsert ){
    if( IsVirtual(pTab) ){
      sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
              pTab->zName);
      goto insert_cleanup;
    }
    if( pTab->pSelect ){
      sqlite3ErrorMsg(pParse, "cannot UPSERT a view");
      goto insert_cleanup;
    }
    if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){
      goto insert_cleanup;
    }
    pTabList->a[0].iCursor = iDataCur;
    pUpsert->pUpsertSrc = pTabList;
    pUpsert->regData = regData;
    pUpsert->iDataCur = iDataCur;
119012
119013
119014
119015
119016
119017
119018

119019
119020
119021
119022
119023
119024
119025
    ** following pseudocode (template 3):
    **
    **      C: yield X, at EOF goto D
    **         insert the select result into <table> from R..R+n
    **         goto C
    **      D: ...
    */

    addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
    VdbeCoverage(v);
    if( ipkColumn>=0 ){
      /* tag-20191021-001: If the INTEGER PRIMARY KEY is being generated by the
      ** SELECT, go ahead and copy the value into the rowid slot now, so that
      ** the value does not get overwritten by a NULL at tag-20191021-002. */
      sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);







>







120271
120272
120273
120274
120275
120276
120277
120278
120279
120280
120281
120282
120283
120284
120285
    ** following pseudocode (template 3):
    **
    **      C: yield X, at EOF goto D
    **         insert the select result into <table> from R..R+n
    **         goto C
    **      D: ...
    */
    sqlite3VdbeReleaseRegisters(pParse, regData, pTab->nCol, 0, 0);
    addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
    VdbeCoverage(v);
    if( ipkColumn>=0 ){
      /* tag-20191021-001: If the INTEGER PRIMARY KEY is being generated by the
      ** SELECT, go ahead and copy the value into the rowid slot now, so that
      ** the value does not get overwritten by a NULL at tag-20191021-002. */
      sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
119209
119210
119211
119212
119213
119214
119215
119216
119217
119218
119219
119220
119221
119222
119223
119224
119225
119226
    }
    autoIncStep(pParse, regAutoinc, regRowid);

#ifndef SQLITE_OMIT_GENERATED_COLUMNS
    /* Compute the new value for generated columns after all other
    ** columns have already been computed.  This must be done after
    ** computing the ROWID in case one of the generated columns
    ** refers to the ROWID. */
    if( pTab->tabFlags & TF_HasGenerated ){
      testcase( pTab->tabFlags & TF_HasVirtual );
      testcase( pTab->tabFlags & TF_HasStored );
      sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab);
    }
#endif

    /* Generate code to check constraints and generate index keys and
    ** do the insertion.
    */







|

<
<







120469
120470
120471
120472
120473
120474
120475
120476
120477


120478
120479
120480
120481
120482
120483
120484
    }
    autoIncStep(pParse, regAutoinc, regRowid);

#ifndef SQLITE_OMIT_GENERATED_COLUMNS
    /* Compute the new value for generated columns after all other
    ** columns have already been computed.  This must be done after
    ** computing the ROWID in case one of the generated columns
    ** is derived from the INTEGER PRIMARY KEY. */
    if( pTab->tabFlags & TF_HasGenerated ){


      sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab);
    }
#endif

    /* Generate code to check constraints and generate index keys and
    ** do the insertion.
    */
119274
119275
119276
119277
119278
119279
119280









119281
119282
119283
119284
119285
119286
119287
  sqlite3VdbeResolveLabel(v, endOfLoop);
  if( useTempTable ){
    sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v);
    sqlite3VdbeJumpHere(v, addrInsTop);
    sqlite3VdbeAddOp1(v, OP_Close, srcTab);
  }else if( pSelect ){
    sqlite3VdbeGoto(v, addrCont);









    sqlite3VdbeJumpHere(v, addrInsTop);
  }

insert_end:
  /* Update the sqlite_sequence table by storing the content of the
  ** maximum rowid counter values recorded while inserting into
  ** autoincrement tables.







>
>
>
>
>
>
>
>
>







120532
120533
120534
120535
120536
120537
120538
120539
120540
120541
120542
120543
120544
120545
120546
120547
120548
120549
120550
120551
120552
120553
120554
  sqlite3VdbeResolveLabel(v, endOfLoop);
  if( useTempTable ){
    sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v);
    sqlite3VdbeJumpHere(v, addrInsTop);
    sqlite3VdbeAddOp1(v, OP_Close, srcTab);
  }else if( pSelect ){
    sqlite3VdbeGoto(v, addrCont);
#ifdef SQLITE_DEBUG
    /* If we are jumping back to an OP_Yield that is preceded by an
    ** OP_ReleaseReg, set the p5 flag on the OP_Goto so that the
    ** OP_ReleaseReg will be included in the loop. */
    if( sqlite3VdbeGetOp(v, addrCont-1)->opcode==OP_ReleaseReg ){
      assert( sqlite3VdbeGetOp(v, addrCont)->opcode==OP_Yield );
      sqlite3VdbeChangeP5(v, 1);
    }
#endif
    sqlite3VdbeJumpHere(v, addrInsTop);
  }

insert_end:
  /* Update the sqlite_sequence table by storing the content of the
  ** maximum rowid counter values recorded while inserting into
  ** autoincrement tables.
119496
119497
119498
119499
119500
119501
119502
119503
119504
119505
119506
119507
119508
119509
119510
  Index *pIdx;         /* Pointer to one of the indices */
  Index *pPk = 0;      /* The PRIMARY KEY index */
  sqlite3 *db;         /* Database connection */
  int i;               /* loop counter */
  int ix;              /* Index loop counter */
  int nCol;            /* Number of columns */
  int onError;         /* Conflict resolution strategy */
  int addr1;           /* Address of jump instruction */
  int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
  int nPkField;        /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
  Index *pUpIdx = 0;   /* Index to which to apply the upsert */
  u8 isUpdate;         /* True if this is an UPDATE operation */
  u8 bAffinityDone = 0;  /* True if the OP_Affinity operation has been run */
  int upsertBypass = 0;  /* Address of Goto to bypass upsert subroutine */
  int upsertJump = 0;    /* Address of Goto that jumps into upsert subroutine */







<







120763
120764
120765
120766
120767
120768
120769

120770
120771
120772
120773
120774
120775
120776
  Index *pIdx;         /* Pointer to one of the indices */
  Index *pPk = 0;      /* The PRIMARY KEY index */
  sqlite3 *db;         /* Database connection */
  int i;               /* loop counter */
  int ix;              /* Index loop counter */
  int nCol;            /* Number of columns */
  int onError;         /* Conflict resolution strategy */

  int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
  int nPkField;        /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
  Index *pUpIdx = 0;   /* Index to which to apply the upsert */
  u8 isUpdate;         /* True if this is an UPDATE operation */
  u8 bAffinityDone = 0;  /* True if the OP_Affinity operation has been run */
  int upsertBypass = 0;  /* Address of Goto to bypass upsert subroutine */
  int upsertJump = 0;    /* Address of Goto that jumps into upsert subroutine */
119540
119541
119542
119543
119544
119545
119546




119547
119548


119549
119550
119551
119552
119553





119554
119555
119556
119557
119558
119559
119560
119561
119562
119563






119564


119565



119566
119567
119568
119569
119570
119571
119572
119573
119574
119575
119576
119577
119578
119579

119580
119581
119582
119583
119584
119585
119586

119587
119588
119589
119590
119591
119592
119593
119594
119595
119596
119597
119598
119599
119600
119601
119602
119603
119604
119605
119606
119607
119608
119609






119610









119611



119612
119613
119614
119615
119616
119617
119618
119619
119620
119621

119622
119623
119624
119625
119626
119627
119628




119629
119630
119631


119632


119633
119634
119635
119636
119637
119638
119639
119640
119641
119642
119643
  /* Record that this module has started */
  VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
                     iDataCur, iIdxCur, regNewData, regOldData, pkChng));

  /* Test all NOT NULL constraints.
  */
  if( pTab->tabFlags & TF_HasNotNull ){




    for(i=0; i<nCol; i++){
      int iReg;


      onError = pTab->aCol[i].notNull;
      if( onError==OE_None ) continue; /* No NOT NULL on this column */
      if( i==pTab->iPKey ){
        continue;        /* ROWID is never NULL */
      }





      if( aiChng && aiChng[i]<0 ){
        /* Don't bother checking for NOT NULL on columns that do not change */
        continue;
      }
      if( overrideError!=OE_Default ){
        onError = overrideError;
      }else if( onError==OE_Default ){
        onError = OE_Abort;
      }
      if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){






        onError = OE_Abort;


      }



      assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
          || onError==OE_Ignore || onError==OE_Replace );
      addr1 = 0;
      testcase( i!=sqlite3TableColumnToStorage(pTab, i) );
      testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL );
      testcase( pTab->aCol[i].colFlags & COLFLAG_STORED );
      iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1;
      switch( onError ){
        case OE_Replace: {
          assert( onError==OE_Replace );
          addr1 = sqlite3VdbeMakeLabel(pParse);
          sqlite3VdbeAddOp2(v, OP_NotNull, iReg, addr1);
            VdbeCoverage(v);
          if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ){

            sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
            sqlite3VdbeAddOp2(v, OP_NotNull, iReg, addr1);
              VdbeCoverage(v);
          }
          onError = OE_Abort;
          /* Fall through into the OE_Abort case to generate code that runs
          ** if both the input and the default value are NULL */

        }
        case OE_Abort:
          sqlite3MayAbort(pParse);
          /* Fall through */
        case OE_Rollback:
        case OE_Fail: {
          char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
                                      pTab->aCol[i].zName);
          sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
                            onError, iReg);
          sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
          sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
          VdbeCoverage(v);
          if( addr1 ) sqlite3VdbeResolveLabel(v, addr1);
          break;
        }
        default: {
          assert( onError==OE_Ignore );
          sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest);
          VdbeCoverage(v);
          break;
        }
      }






    }









  }




  /* Test all CHECK constraints
  */
#ifndef SQLITE_OMIT_CHECK
  if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
    ExprList *pCheck = pTab->pCheck;
    pParse->iSelfTab = -(regNewData+1);
    onError = overrideError!=OE_Default ? overrideError : OE_Abort;
    for(i=0; i<pCheck->nExpr; i++){
      int allOk;

      Expr *pExpr = pCheck->a[i].pExpr;
      if( aiChng
       && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng)
      ){
        /* The check constraints do not reference any of the columns being
        ** updated so there is no point it verifying the check constraint */
        continue;




      }
      allOk = sqlite3VdbeMakeLabel(pParse);
      sqlite3VdbeVerifyAbortable(v, onError);


      sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);


      if( onError==OE_Ignore ){
        sqlite3VdbeGoto(v, ignoreDest);
      }else{
        char *zName = pCheck->a[i].zName;
        if( zName==0 ) zName = pTab->zName;
        if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */
        sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
                              onError, zName, P4_TRANSIENT,
                              P5_ConstraintCheck);
      }
      sqlite3VdbeResolveLabel(v, allOk);







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

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










>







>
>
>
>



>
>
|
>
>



|







120806
120807
120808
120809
120810
120811
120812
120813
120814
120815
120816
120817
120818
120819
120820
120821
120822
120823
120824
120825
120826
120827
120828
120829
120830
120831
120832
120833
120834
120835
120836
120837
120838
120839
120840
120841
120842
120843
120844
120845
120846
120847
120848
120849
120850
120851
120852
120853
120854
120855

120856


120857
120858
120859

120860

120861
120862
120863
120864
120865





120866
120867
120868
120869
120870
120871
120872
120873
120874
120875
120876
120877
120878
120879

120880
120881
120882
120883
120884
120885
120886
120887
120888
120889
120890
120891
120892
120893
120894
120895
120896
120897
120898
120899
120900
120901
120902
120903
120904
120905
120906
120907
120908
120909
120910
120911
120912
120913
120914
120915
120916
120917
120918
120919
120920
120921
120922
120923
120924
120925
120926
120927
120928
120929
120930
120931
120932
120933
120934
120935
120936
120937
120938
120939
120940
120941
120942
120943
120944
120945
120946
120947
120948
120949
  /* Record that this module has started */
  VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
                     iDataCur, iIdxCur, regNewData, regOldData, pkChng));

  /* Test all NOT NULL constraints.
  */
  if( pTab->tabFlags & TF_HasNotNull ){
    int b2ndPass = 0;         /* True if currently running 2nd pass */
    int nSeenReplace = 0;     /* Number of ON CONFLICT REPLACE operations */
    int nGenerated = 0;       /* Number of generated columns with NOT NULL */
    while(1){  /* Make 2 passes over columns. Exit loop via "break" */
      for(i=0; i<nCol; i++){
        int iReg;                        /* Register holding column value */
        Column *pCol = &pTab->aCol[i];   /* The column to check for NOT NULL */
        int isGenerated;                 /* non-zero if column is generated */
        onError = pCol->notNull;
        if( onError==OE_None ) continue; /* No NOT NULL on this column */
        if( i==pTab->iPKey ){
          continue;        /* ROWID is never NULL */
        }
        isGenerated = pCol->colFlags & COLFLAG_GENERATED;
        if( isGenerated && !b2ndPass ){
          nGenerated++;
          continue;        /* Generated columns processed on 2nd pass */
        }
        if( aiChng && aiChng[i]<0 && !isGenerated ){
          /* Do not check NOT NULL on columns that do not change */
          continue;
        }
        if( overrideError!=OE_Default ){
          onError = overrideError;
        }else if( onError==OE_Default ){
          onError = OE_Abort;
        }
        if( onError==OE_Replace ){
          if( b2ndPass        /* REPLACE becomes ABORT on the 2nd pass */
           || pCol->pDflt==0  /* REPLACE is ABORT if no DEFAULT value */
          ){
            testcase( pCol->colFlags & COLFLAG_VIRTUAL );
            testcase( pCol->colFlags & COLFLAG_STORED );
            testcase( pCol->colFlags & COLFLAG_GENERATED );
            onError = OE_Abort;
          }else{
            assert( !isGenerated );
          }
        }else if( b2ndPass && !isGenerated ){
          continue;
        }
        assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
            || onError==OE_Ignore || onError==OE_Replace );

        testcase( i!=sqlite3TableColumnToStorage(pTab, i) );


        iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1;
        switch( onError ){
          case OE_Replace: {

            int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, iReg);

            VdbeCoverage(v);
            assert( (pCol->colFlags & COLFLAG_GENERATED)==0 );
            nSeenReplace++;
            sqlite3ExprCodeCopy(pParse, pCol->pDflt, iReg);
            sqlite3VdbeJumpHere(v, addr1);





            break;
          }
          case OE_Abort:
            sqlite3MayAbort(pParse);
            /* Fall through */
          case OE_Rollback:
          case OE_Fail: {
            char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
                                        pCol->zName);
            sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
                              onError, iReg);
            sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
            sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
            VdbeCoverage(v);

            break;
          }
          default: {
            assert( onError==OE_Ignore );
            sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest);
            VdbeCoverage(v);
            break;
          }
        } /* end switch(onError) */
      } /* end loop i over columns */
      if( nGenerated==0 && nSeenReplace==0 ){
        /* If there are no generated columns with NOT NULL constraints
        ** and no NOT NULL ON CONFLICT REPLACE constraints, then a single
        ** pass is sufficient */
        break;
      }
      if( b2ndPass ) break;  /* Never need more than 2 passes */
      b2ndPass = 1;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
      if( nSeenReplace>0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){
        /* If any NOT NULL ON CONFLICT REPLACE constraints fired on the
        ** first pass, recomputed values for all generated columns, as
        ** those values might depend on columns affected by the REPLACE.
        */
        sqlite3ComputeGeneratedColumns(pParse, regNewData+1, pTab);
      }
#endif
    } /* end of 2-pass loop */
  } /* end if( has-not-null-constraints ) */

  /* Test all CHECK constraints
  */
#ifndef SQLITE_OMIT_CHECK
  if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
    ExprList *pCheck = pTab->pCheck;
    pParse->iSelfTab = -(regNewData+1);
    onError = overrideError!=OE_Default ? overrideError : OE_Abort;
    for(i=0; i<pCheck->nExpr; i++){
      int allOk;
      Expr *pCopy;
      Expr *pExpr = pCheck->a[i].pExpr;
      if( aiChng
       && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng)
      ){
        /* The check constraints do not reference any of the columns being
        ** updated so there is no point it verifying the check constraint */
        continue;
      }
      if( bAffinityDone==0 ){
        sqlite3TableAffinity(v, pTab, regNewData+1);
        bAffinityDone = 1;
      }
      allOk = sqlite3VdbeMakeLabel(pParse);
      sqlite3VdbeVerifyAbortable(v, onError);
      pCopy = sqlite3ExprDup(db, pExpr, 0);
      if( !db->mallocFailed ){
        sqlite3ExprIfTrue(pParse, pCopy, allOk, SQLITE_JUMPIFNULL);
      }
      sqlite3ExprDelete(db, pCopy);
      if( onError==OE_Ignore ){
        sqlite3VdbeGoto(v, ignoreDest);
      }else{
        char *zName = pCheck->a[i].zEName;
        if( zName==0 ) zName = pTab->zName;
        if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */
        sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
                              onError, zName, P4_TRANSIENT,
                              P5_ConstraintCheck);
      }
      sqlite3VdbeResolveLabel(v, allOk);
119932
119933
119934
119935
119936
119937
119938

119939
119940
119941
119942
119943
119944
119945
    sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
    VdbeComment((v, "for %s", pIdx->zName));
#ifdef SQLITE_ENABLE_NULL_TRIM
    if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
      sqlite3SetMakeRecordP5(v, pIdx->pTable);
    }
#endif


    /* In an UPDATE operation, if this index is the PRIMARY KEY index 
    ** of a WITHOUT ROWID table and there has been no change the
    ** primary key, then no collision is possible.  The collision detection
    ** logic below can all be skipped. */
    if( isUpdate && pPk==pIdx && pkChng==0 ){
      sqlite3VdbeResolveLabel(v, addrUniqueOk);







>







121238
121239
121240
121241
121242
121243
121244
121245
121246
121247
121248
121249
121250
121251
121252
    sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
    VdbeComment((v, "for %s", pIdx->zName));
#ifdef SQLITE_ENABLE_NULL_TRIM
    if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
      sqlite3SetMakeRecordP5(v, pIdx->pTable);
    }
#endif
    sqlite3VdbeReleaseRegisters(pParse, regIdx, pIdx->nColumn, 0, 0);

    /* In an UPDATE operation, if this index is the PRIMARY KEY index 
    ** of a WITHOUT ROWID table and there has been no change the
    ** primary key, then no collision is possible.  The collision detection
    ** logic below can all be skipped. */
    if( isUpdate && pPk==pIdx && pkChng==0 ){
      sqlite3VdbeResolveLabel(v, addrUniqueOk);
120085
120086
120087
120088
120089
120090
120091



120092
120093
120094



120095
120096
120097
120098
120099
120100
120101
        nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk;
        assert( nConflictCk>0 );
        testcase( nConflictCk>1 );
        if( regTrigCnt ){
          sqlite3MultiWrite(pParse);
          nReplaceTrig++;
        }



        sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
            regR, nPkField, 0, OE_Replace,
            (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);



        if( regTrigCnt ){
          int addrBypass;  /* Jump destination to bypass recheck logic */

          sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */
          addrBypass = sqlite3VdbeAddOp0(v, OP_Goto);  /* Bypass recheck */
          VdbeComment((v, "bypass recheck"));








>
>
>



>
>
>







121392
121393
121394
121395
121396
121397
121398
121399
121400
121401
121402
121403
121404
121405
121406
121407
121408
121409
121410
121411
121412
121413
121414
        nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk;
        assert( nConflictCk>0 );
        testcase( nConflictCk>1 );
        if( regTrigCnt ){
          sqlite3MultiWrite(pParse);
          nReplaceTrig++;
        }
        if( pTrigger && isUpdate ){
          sqlite3VdbeAddOp1(v, OP_CursorLock, iDataCur);
        }
        sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
            regR, nPkField, 0, OE_Replace,
            (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
        if( pTrigger && isUpdate ){
          sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur);
        }
        if( regTrigCnt ){
          int addrBypass;  /* Jump destination to bypass recheck logic */

          sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */
          addrBypass = sqlite3VdbeAddOp0(v, OP_Goto);  /* Bypass recheck */
          VdbeComment((v, "bypass recheck"));

120117
120118
120119
120120
120121
120122
120123

120124
120125
120126
120127
120128

120129
120130
120131
120132
120133
120134
120135
120136
            VdbeOp x;    /* Conflict check opcode to copy */
            /* The sqlite3VdbeAddOp4() call might reallocate the opcode array.
            ** Hence, make a complete copy of the opcode, rather than using
            ** a pointer to the opcode. */
            x = *sqlite3VdbeGetOp(v, addrConflictCk);
            if( x.opcode!=OP_IdxRowid ){
              int p2;      /* New P2 value for copied conflict check opcode */

              if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){
                p2 = lblRecheckOk;
              }else{
                p2 = x.p2;
              }

              sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, x.p4.z, x.p4type);
              sqlite3VdbeChangeP5(v, x.p5);
              VdbeCoverageIf(v, p2!=x.p2);
            }
            nConflictCk--;
            addrConflictCk++;
          }
          /* If the retest fails, issue an abort */







>





>
|







121430
121431
121432
121433
121434
121435
121436
121437
121438
121439
121440
121441
121442
121443
121444
121445
121446
121447
121448
121449
121450
121451
            VdbeOp x;    /* Conflict check opcode to copy */
            /* The sqlite3VdbeAddOp4() call might reallocate the opcode array.
            ** Hence, make a complete copy of the opcode, rather than using
            ** a pointer to the opcode. */
            x = *sqlite3VdbeGetOp(v, addrConflictCk);
            if( x.opcode!=OP_IdxRowid ){
              int p2;      /* New P2 value for copied conflict check opcode */
              const char *zP4;
              if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){
                p2 = lblRecheckOk;
              }else{
                p2 = x.p2;
              }
              zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z;
              sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type);
              sqlite3VdbeChangeP5(v, x.p5);
              VdbeCoverageIf(v, p2!=x.p2);
            }
            nConflictCk--;
            addrConflictCk++;
          }
          /* If the retest fails, issue an abort */
120244
120245
120246
120247
120248
120249
120250




120251
120252
120253
120254
120255
120256
120257
       || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
  );

  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){




    if( aRegIdx[i]==0 ) continue;
    if( pIdx->pPartIdxWhere ){
      sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
      VdbeCoverage(v);
    }
    pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){







>
>
>
>







121559
121560
121561
121562
121563
121564
121565
121566
121567
121568
121569
121570
121571
121572
121573
121574
121575
121576
       || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
  );

  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    /* All REPLACE indexes are at the end of the list */
    assert( pIdx->onError!=OE_Replace
         || pIdx->pNext==0
         || pIdx->pNext->onError==OE_Replace );
    if( aRegIdx[i]==0 ) continue;
    if( pIdx->pPartIdxWhere ){
      sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
      VdbeCoverage(v);
    }
    pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
120726
120727
120728
120729
120730
120731
120732
120733
120734
120735
120736
120737
120738
120739
120740

120741
120742
120743
120744
120745
120746
120747
      autoIncStep(pParse, regAutoinc, regRowid);
    }else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
      addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
    }else{
      addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
      assert( (pDest->tabFlags & TF_Autoincrement)==0 );
    }
    sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
    if( db->mDbFlags & DBFLAG_Vacuum ){
      sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
      insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
                           OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
    }else{
      insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
    }

    sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
                      (char*)pDest, P4_TABLE);
    sqlite3VdbeChangeP5(v, insFlags);
    sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
    sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
  }else{







<


<
|



>







122045
122046
122047
122048
122049
122050
122051

122052
122053

122054
122055
122056
122057
122058
122059
122060
122061
122062
122063
122064
122065
      autoIncStep(pParse, regAutoinc, regRowid);
    }else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
      addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
    }else{
      addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
      assert( (pDest->tabFlags & TF_Autoincrement)==0 );
    }

    if( db->mDbFlags & DBFLAG_Vacuum ){
      sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);

      insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
    }else{
      insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
    }
    sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
    sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
                      (char*)pDest, P4_TABLE);
    sqlite3VdbeChangeP5(v, insFlags);
    sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
    sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
  }else{
120758
120759
120760
120761
120762
120763
120764
120765
120766
120767
120768
120769
120770
120771
120772
    sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx);
    VdbeComment((v, "%s", pSrcIdx->zName));
    sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest);
    sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx);
    sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
    VdbeComment((v, "%s", pDestIdx->zName));
    addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
    sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
    if( db->mDbFlags & DBFLAG_Vacuum ){
      /* This INSERT command is part of a VACUUM operation, which guarantees
      ** that the destination table is empty. If all indexed columns use
      ** collation sequence BINARY, then it can also be assumed that the
      ** index will be populated by inserting keys in strictly sorted 
      ** order. In this case, instead of seeking within the b-tree as part
      ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the







<







122076
122077
122078
122079
122080
122081
122082

122083
122084
122085
122086
122087
122088
122089
    sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx);
    VdbeComment((v, "%s", pSrcIdx->zName));
    sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest);
    sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx);
    sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
    VdbeComment((v, "%s", pDestIdx->zName));
    addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);

    if( db->mDbFlags & DBFLAG_Vacuum ){
      /* This INSERT command is part of a VACUUM operation, which guarantees
      ** that the destination table is empty. If all indexed columns use
      ** collation sequence BINARY, then it can also be assumed that the
      ** index will be populated by inserting keys in strictly sorted 
      ** order. In this case, instead of seeking within the b-tree as part
      ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the
120782
120783
120784
120785
120786
120787
120788
120789
120790
120791
120792

120793
120794
120795
120796
120797
120798
120799
        const char *zColl = pSrcIdx->azColl[i];
        if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
      }
      if( i==pSrcIdx->nColumn ){
        idxInsFlags = OPFLAG_USESEEKRESULT;
        sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
      }
    }
    if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
      idxInsFlags |= OPFLAG_NCHANGE;
    }

    sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
    sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
    sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
    sqlite3VdbeJumpHere(v, addr1);
    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
    sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
  }







<
|


>







122099
122100
122101
122102
122103
122104
122105

122106
122107
122108
122109
122110
122111
122112
122113
122114
122115
122116
        const char *zColl = pSrcIdx->azColl[i];
        if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
      }
      if( i==pSrcIdx->nColumn ){
        idxInsFlags = OPFLAG_USESEEKRESULT;
        sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
      }

    }else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
      idxInsFlags |= OPFLAG_NCHANGE;
    }
    sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
    sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
    sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
    sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
    sqlite3VdbeJumpHere(v, addr1);
    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
    sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
  }
121300
121301
121302
121303
121304
121305
121306

121307








121308
121309
121310
121311
121312
121313
121314
  /* Version 3.26.0 and later */
  const char *(*normalized_sql)(sqlite3_stmt*);
  /* Version 3.28.0 and later */
  int (*stmt_isexplain)(sqlite3_stmt*);
  int (*value_frombind)(sqlite3_value*);
  /* Version 3.30.0 and later */
  int (*drop_modules)(sqlite3*,const char**);

  sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);








};

/*
** This is the function signature used for all extension entry points.  It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(







>

>
>
>
>
>
>
>
>







122617
122618
122619
122620
122621
122622
122623
122624
122625
122626
122627
122628
122629
122630
122631
122632
122633
122634
122635
122636
122637
122638
122639
122640
  /* Version 3.26.0 and later */
  const char *(*normalized_sql)(sqlite3_stmt*);
  /* Version 3.28.0 and later */
  int (*stmt_isexplain)(sqlite3_stmt*);
  int (*value_frombind)(sqlite3_value*);
  /* Version 3.30.0 and later */
  int (*drop_modules)(sqlite3*,const char**);
  /* Version 3.31.0 and later */
  sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
  const char *(*uri_key)(const char*,int);
  const char *(*filename_database)(const char*);
  const char *(*filename_journal)(const char*);
  const char *(*filename_wal)(const char*);
  /* Version 3.32.0 and later */
  char *(*create_filename)(const char*,const char*,const char*,
                           int,const char**);
  void (*free_filename)(char*);
};

/*
** This is the function signature used for all extension entry points.  It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
121591
121592
121593
121594
121595
121596
121597
121598
121599
121600
121601

121602







121603
121604
121605
121606
121607
121608
121609
#define sqlite3_str_length             sqlite3_api->str_length
#define sqlite3_str_value              sqlite3_api->str_value
/* Version 3.25.0 and later */
#define sqlite3_create_window_function sqlite3_api->create_window_function
/* Version 3.26.0 and later */
#define sqlite3_normalized_sql         sqlite3_api->normalized_sql
/* Version 3.28.0 and later */
#define sqlite3_stmt_isexplain         sqlite3_api->isexplain
#define sqlite3_value_frombind         sqlite3_api->frombind
/* Version 3.30.0 and later */
#define sqlite3_drop_modules           sqlite3_api->drop_modules

#define sqlite3_hard_heap_limit64      sqlite3_api->hard_heap_limit64







#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */

#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
  /* This case when the file really is being compiled as a loadable 
  ** extension */
# define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v)  sqlite3_api=v;







|
|


>

>
>
>
>
>
>
>







122917
122918
122919
122920
122921
122922
122923
122924
122925
122926
122927
122928
122929
122930
122931
122932
122933
122934
122935
122936
122937
122938
122939
122940
122941
122942
122943
#define sqlite3_str_length             sqlite3_api->str_length
#define sqlite3_str_value              sqlite3_api->str_value
/* Version 3.25.0 and later */
#define sqlite3_create_window_function sqlite3_api->create_window_function
/* Version 3.26.0 and later */
#define sqlite3_normalized_sql         sqlite3_api->normalized_sql
/* Version 3.28.0 and later */
#define sqlite3_stmt_isexplain         sqlite3_api->stmt_isexplain
#define sqlite3_value_frombind         sqlite3_api->value_frombind
/* Version 3.30.0 and later */
#define sqlite3_drop_modules           sqlite3_api->drop_modules
/* Version 3.31.0 and later */
#define sqlite3_hard_heap_limit64      sqlite3_api->hard_heap_limit64
#define sqlite3_uri_key                sqlite3_api->uri_key
#define sqlite3_filename_database      sqlite3_api->filename_database
#define sqlite3_filename_journal       sqlite3_api->filename_journal
#define sqlite3_filename_wal           sqlite3_api->filename_wal
/* Version 3.32.0 and later */
#define sqlite3_create_filename        sqlite3_api->create_filename
#define sqlite3_free_filename          sqlite3_api->free_filename
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */

#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
  /* This case when the file really is being compiled as a loadable 
  ** extension */
# define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v)  sqlite3_api=v;
122070
122071
122072
122073
122074
122075
122076







122077
122078
122079
122080
122081
122082
122083
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3_drop_modules,
#else
  0,
#endif
  /* Version 3.31.0 and later */
  sqlite3_hard_heap_limit64,







};

/*
** Attempt to load an SQLite extension library contained in the file
** zFile.  The entry point is zProc.  zProc may be 0 in which case a
** default entry point name (sqlite3_extension_init) is used.  Use
** of the default name is recommended.







>
>
>
>
>
>
>







123404
123405
123406
123407
123408
123409
123410
123411
123412
123413
123414
123415
123416
123417
123418
123419
123420
123421
123422
123423
123424
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3_drop_modules,
#else
  0,
#endif
  /* Version 3.31.0 and later */
  sqlite3_hard_heap_limit64,
  sqlite3_uri_key,
  sqlite3_filename_database,
  sqlite3_filename_journal,
  sqlite3_filename_wal,
  /* Version 3.32.0 and later */
  sqlite3_create_filename,
  sqlite3_free_filename,
};

/*
** Attempt to load an SQLite extension library contained in the file
** zFile.  The entry point is zProc.  zProc may be 0 in which case a
** default entry point name (sqlite3_extension_init) is used.  Use
** of the default name is recommended.
122476
122477
122478
122479
122480
122481
122482

122483
122484
122485
122486
122487
122488
122489
122490
122491
122492
122493
122494
122495
122496
122497
122498
122499
122500
122501
122502
122503
122504
122505
122506
122507
122508
122509
122510
122511
122512
122513
122514
122515
122516
122517
122518
122519
122520
122521
122522
122523
122524
122525
122526
122527
122528
122529
122530
122531
122532
122533
122534
/* DO NOT EDIT!
** This file is automatically generated by the script at
** ../tool/mkpragmatab.tcl.  To update the set of pragmas, edit
** that script and rerun it.
*/

/* The various pragma types */

#define PragTyp_HEADER_VALUE                   0
#define PragTyp_AUTO_VACUUM                    1
#define PragTyp_FLAG                           2
#define PragTyp_BUSY_TIMEOUT                   3
#define PragTyp_CACHE_SIZE                     4
#define PragTyp_CACHE_SPILL                    5
#define PragTyp_CASE_SENSITIVE_LIKE            6
#define PragTyp_COLLATION_LIST                 7
#define PragTyp_COMPILE_OPTIONS                8
#define PragTyp_DATA_STORE_DIRECTORY           9
#define PragTyp_DATABASE_LIST                 10
#define PragTyp_DEFAULT_CACHE_SIZE            11
#define PragTyp_ENCODING                      12
#define PragTyp_FOREIGN_KEY_CHECK             13
#define PragTyp_FOREIGN_KEY_LIST              14
#define PragTyp_FUNCTION_LIST                 15
#define PragTyp_HARD_HEAP_LIMIT               16
#define PragTyp_INCREMENTAL_VACUUM            17
#define PragTyp_INDEX_INFO                    18
#define PragTyp_INDEX_LIST                    19
#define PragTyp_INTEGRITY_CHECK               20
#define PragTyp_JOURNAL_MODE                  21
#define PragTyp_JOURNAL_SIZE_LIMIT            22
#define PragTyp_LOCK_PROXY_FILE               23
#define PragTyp_LOCKING_MODE                  24
#define PragTyp_PAGE_COUNT                    25
#define PragTyp_MMAP_SIZE                     26
#define PragTyp_MODULE_LIST                   27
#define PragTyp_OPTIMIZE                      28
#define PragTyp_PAGE_SIZE                     29
#define PragTyp_PRAGMA_LIST                   30
#define PragTyp_SECURE_DELETE                 31
#define PragTyp_SHRINK_MEMORY                 32
#define PragTyp_SOFT_HEAP_LIMIT               33
#define PragTyp_SYNCHRONOUS                   34
#define PragTyp_TABLE_INFO                    35
#define PragTyp_TEMP_STORE                    36
#define PragTyp_TEMP_STORE_DIRECTORY          37
#define PragTyp_THREADS                       38
#define PragTyp_WAL_AUTOCHECKPOINT            39
#define PragTyp_WAL_CHECKPOINT                40
#define PragTyp_ACTIVATE_EXTENSIONS           41
#define PragTyp_KEY                           42
#define PragTyp_LOCK_STATUS                   43
#define PragTyp_STATS                         44

/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
#define PragFlg_NoColumns  0x02 /* OP_ResultRow called with zero columns */
#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
#define PragFlg_ReadOnly   0x08 /* Read-only HEADER_VALUE */
#define PragFlg_Result0    0x10 /* Acts as query when no argument */







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







123817
123818
123819
123820
123821
123822
123823
123824
123825
123826
123827
123828
123829
123830
123831
123832
123833
123834
123835
123836
123837
123838
123839
123840
123841
123842
123843
123844
123845
123846
123847
123848
123849
123850
123851
123852
123853
123854
123855
123856
123857
123858
123859
123860
123861
123862
123863
123864
123865


123866
123867
123868
123869
123870
123871
123872
123873
123874
/* DO NOT EDIT!
** This file is automatically generated by the script at
** ../tool/mkpragmatab.tcl.  To update the set of pragmas, edit
** that script and rerun it.
*/

/* The various pragma types */
#define PragTyp_ACTIVATE_EXTENSIONS            0
#define PragTyp_HEADER_VALUE                   1
#define PragTyp_AUTO_VACUUM                    2
#define PragTyp_FLAG                           3
#define PragTyp_BUSY_TIMEOUT                   4
#define PragTyp_CACHE_SIZE                     5
#define PragTyp_CACHE_SPILL                    6
#define PragTyp_CASE_SENSITIVE_LIKE            7
#define PragTyp_COLLATION_LIST                 8
#define PragTyp_COMPILE_OPTIONS                9
#define PragTyp_DATA_STORE_DIRECTORY          10
#define PragTyp_DATABASE_LIST                 11
#define PragTyp_DEFAULT_CACHE_SIZE            12
#define PragTyp_ENCODING                      13
#define PragTyp_FOREIGN_KEY_CHECK             14
#define PragTyp_FOREIGN_KEY_LIST              15
#define PragTyp_FUNCTION_LIST                 16
#define PragTyp_HARD_HEAP_LIMIT               17
#define PragTyp_INCREMENTAL_VACUUM            18
#define PragTyp_INDEX_INFO                    19
#define PragTyp_INDEX_LIST                    20
#define PragTyp_INTEGRITY_CHECK               21
#define PragTyp_JOURNAL_MODE                  22
#define PragTyp_JOURNAL_SIZE_LIMIT            23
#define PragTyp_LOCK_PROXY_FILE               24
#define PragTyp_LOCKING_MODE                  25
#define PragTyp_PAGE_COUNT                    26
#define PragTyp_MMAP_SIZE                     27
#define PragTyp_MODULE_LIST                   28
#define PragTyp_OPTIMIZE                      29
#define PragTyp_PAGE_SIZE                     30
#define PragTyp_PRAGMA_LIST                   31
#define PragTyp_SECURE_DELETE                 32
#define PragTyp_SHRINK_MEMORY                 33
#define PragTyp_SOFT_HEAP_LIMIT               34
#define PragTyp_SYNCHRONOUS                   35
#define PragTyp_TABLE_INFO                    36
#define PragTyp_TEMP_STORE                    37
#define PragTyp_TEMP_STORE_DIRECTORY          38
#define PragTyp_THREADS                       39
#define PragTyp_WAL_AUTOCHECKPOINT            40
#define PragTyp_WAL_CHECKPOINT                41


#define PragTyp_LOCK_STATUS                   42
#define PragTyp_STATS                         43

/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
#define PragFlg_NoColumns  0x02 /* OP_ResultRow called with zero columns */
#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
#define PragFlg_ReadOnly   0x08 /* Read-only HEADER_VALUE */
#define PragFlg_Result0    0x10 /* Acts as query when no argument */
122559
122560
122561
122562
122563
122564
122565
122566
122567
122568
122569
122570
122571
122572
122573
122574
122575
122576
122577
122578
122579
122580
122581
122582
122583
122584
122585
122586

122587
122588




122589
122590
122591
122592
122593
122594
122595
122596
122597
122598
122599
122600
122601
122602
122603
122604
122605
122606
122607
122608
122609
122610
122611
122612
122613
122614
                           /* table_info reuses 8 */
  /*  15 */ "seqno",       /* Used by: index_xinfo */
  /*  16 */ "cid",        
  /*  17 */ "name",       
  /*  18 */ "desc",       
  /*  19 */ "coll",       
  /*  20 */ "key",        
  /*  21 */ "tbl",         /* Used by: stats */
  /*  22 */ "idx",        
  /*  23 */ "wdth",       
  /*  24 */ "hght",       
  /*  25 */ "flgs",       
  /*  26 */ "seq",         /* Used by: index_list */
  /*  27 */ "name",       
  /*  28 */ "unique",     
  /*  29 */ "origin",     
  /*  30 */ "partial",    
  /*  31 */ "table",       /* Used by: foreign_key_check */
  /*  32 */ "rowid",      
  /*  33 */ "parent",     
  /*  34 */ "fkid",       
                           /* index_info reuses 15 */
  /*  35 */ "seq",         /* Used by: database_list */
  /*  36 */ "name",       
  /*  37 */ "file",       
  /*  38 */ "busy",        /* Used by: wal_checkpoint */
  /*  39 */ "log",        
  /*  40 */ "checkpointed",

  /*  41 */ "name",        /* Used by: function_list */
  /*  42 */ "builtin",    




                           /* collation_list reuses 26 */
  /*  43 */ "database",    /* Used by: lock_status */
  /*  44 */ "status",     
  /*  45 */ "cache_size",  /* Used by: default_cache_size */
                           /* module_list pragma_list reuses 9 */
  /*  46 */ "timeout",     /* Used by: busy_timeout */
};

/* Definitions of all built-in pragmas */
typedef struct PragmaName {
  const char *const zName; /* Name of pragma */
  u8 ePragTyp;             /* PragTyp_XXX value */
  u8 mPragFlg;             /* Zero or more PragFlg_XXX values */
  u8 iPragCName;           /* Start of column names in pragCName[] */
  u8 nPragCName;           /* Num of col names. 0 means use pragma name */
  u64 iArg;                /* Extra argument */
} PragmaName;
static const PragmaName aPragmaName[] = {
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
 {/* zName:     */ "activate_extensions",
  /* ePragTyp:  */ PragTyp_ACTIVATE_EXTENSIONS,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)







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

|












|







123899
123900
123901
123902
123903
123904
123905
123906
123907
123908
123909
123910
123911
123912
123913
123914
123915
123916
123917
123918
123919

123920
123921
123922
123923
123924
123925
123926
123927
123928
123929
123930
123931
123932
123933
123934
123935
123936
123937
123938
123939
123940
123941
123942
123943
123944
123945
123946
123947
123948
123949
123950
123951
123952
123953
123954
123955
123956
123957
123958
                           /* table_info reuses 8 */
  /*  15 */ "seqno",       /* Used by: index_xinfo */
  /*  16 */ "cid",        
  /*  17 */ "name",       
  /*  18 */ "desc",       
  /*  19 */ "coll",       
  /*  20 */ "key",        
  /*  21 */ "name",        /* Used by: function_list */
  /*  22 */ "builtin",    
  /*  23 */ "type",       
  /*  24 */ "enc",        
  /*  25 */ "narg",       
  /*  26 */ "flags",      
  /*  27 */ "tbl",         /* Used by: stats */
  /*  28 */ "idx",        
  /*  29 */ "wdth",       
  /*  30 */ "hght",       
  /*  31 */ "flgs",       
  /*  32 */ "seq",         /* Used by: index_list */
  /*  33 */ "name",       
  /*  34 */ "unique",     

  /*  35 */ "origin",     
  /*  36 */ "partial",    
  /*  37 */ "table",       /* Used by: foreign_key_check */
  /*  38 */ "rowid",      
  /*  39 */ "parent",     
  /*  40 */ "fkid",       
                           /* index_info reuses 15 */
  /*  41 */ "seq",         /* Used by: database_list */
  /*  42 */ "name",       
  /*  43 */ "file",       
  /*  44 */ "busy",        /* Used by: wal_checkpoint */
  /*  45 */ "log",        
  /*  46 */ "checkpointed",
                           /* collation_list reuses 32 */
  /*  47 */ "database",    /* Used by: lock_status */
  /*  48 */ "status",     
  /*  49 */ "cache_size",  /* Used by: default_cache_size */
                           /* module_list pragma_list reuses 9 */
  /*  50 */ "timeout",     /* Used by: busy_timeout */
};

/* Definitions of all built-in pragmas */
typedef struct PragmaName {
  const char *const zName; /* Name of pragma */
  u8 ePragTyp;             /* PragTyp_XXX value */
  u8 mPragFlg;             /* Zero or more PragFlg_XXX values */
  u8 iPragCName;           /* Start of column names in pragCName[] */
  u8 nPragCName;           /* Num of col names. 0 means use pragma name */
  u64 iArg;                /* Extra argument */
} PragmaName;
static const PragmaName aPragmaName[] = {
#if defined(SQLITE_ENABLE_CEROD)
 {/* zName:     */ "activate_extensions",
  /* ePragTyp:  */ PragTyp_ACTIVATE_EXTENSIONS,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
122633
122634
122635
122636
122637
122638
122639
122640
122641
122642
122643
122644
122645
122646
122647
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_AutoIndex },
#endif
#endif
 {/* zName:     */ "busy_timeout",
  /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 46, 1,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "cache_size",
  /* ePragTyp:  */ PragTyp_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },







|







123977
123978
123979
123980
123981
123982
123983
123984
123985
123986
123987
123988
123989
123990
123991
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_AutoIndex },
#endif
#endif
 {/* zName:     */ "busy_timeout",
  /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 50, 1,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "cache_size",
  /* ePragTyp:  */ PragTyp_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
122672
122673
122674
122675
122676
122677
122678
122679
122680
122681
122682
122683
122684
122685
122686
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_CkptFullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "collation_list",
  /* ePragTyp:  */ PragTyp_COLLATION_LIST,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 26, 2,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
 {/* zName:     */ "compile_options",
  /* ePragTyp:  */ PragTyp_COMPILE_OPTIONS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,







|







124016
124017
124018
124019
124020
124021
124022
124023
124024
124025
124026
124027
124028
124029
124030
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_CkptFullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "collation_list",
  /* ePragTyp:  */ PragTyp_COLLATION_LIST,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 32, 2,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
 {/* zName:     */ "compile_options",
  /* ePragTyp:  */ PragTyp_COMPILE_OPTIONS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
122707
122708
122709
122710
122711
122712
122713
122714
122715
122716
122717
122718
122719
122720
122721
122722
122723
122724
122725
122726
122727
122728
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "database_list",
  /* ePragTyp:  */ PragTyp_DATABASE_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
  /* ColNames:  */ 35, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
 {/* zName:     */ "default_cache_size",
  /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 45, 1,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "defer_foreign_keys",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,







|






|







124051
124052
124053
124054
124055
124056
124057
124058
124059
124060
124061
124062
124063
124064
124065
124066
124067
124068
124069
124070
124071
124072
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "database_list",
  /* ePragTyp:  */ PragTyp_DATABASE_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
  /* ColNames:  */ 41, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
 {/* zName:     */ "default_cache_size",
  /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 49, 1,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "defer_foreign_keys",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
122744
122745
122746
122747
122748
122749
122750
122751
122752
122753
122754
122755
122756
122757
122758
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "foreign_key_check",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
  /* ColNames:  */ 31, 4,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
 {/* zName:     */ "foreign_key_list",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 0, 8,







|







124088
124089
124090
124091
124092
124093
124094
124095
124096
124097
124098
124099
124100
124101
124102
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "foreign_key_check",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
  /* ColNames:  */ 37, 4,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
 {/* zName:     */ "foreign_key_list",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 0, 8,
122787
122788
122789
122790
122791
122792
122793
122794
122795
122796
122797
122798
122799
122800
122801
122802
122803
122804
122805
122806
122807
122808
122809
122810
122811
122812
122813
122814
122815
122816
122817
122818
122819
122820
122821
  /* iArg:      */ SQLITE_FullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
 {/* zName:     */ "function_list",
  /* ePragTyp:  */ PragTyp_FUNCTION_LIST,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 41, 2,
  /* iArg:      */ 0 },
#endif
#endif
 {/* zName:     */ "hard_heap_limit",
  /* ePragTyp:  */ PragTyp_HARD_HEAP_LIMIT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#if defined(SQLITE_HAS_CODEC)
 {/* zName:     */ "hexkey",
  /* ePragTyp:  */ PragTyp_KEY,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 2 },
 {/* zName:     */ "hexrekey",
  /* ePragTyp:  */ PragTyp_KEY,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 3 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_CHECK)
 {/* zName:     */ "ignore_check_constraints",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_IgnoreChecks },







|








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







124131
124132
124133
124134
124135
124136
124137
124138
124139
124140
124141
124142
124143
124144
124145
124146












124147
124148
124149
124150
124151
124152
124153
  /* iArg:      */ SQLITE_FullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
 {/* zName:     */ "function_list",
  /* ePragTyp:  */ PragTyp_FUNCTION_LIST,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 21, 6,
  /* iArg:      */ 0 },
#endif
#endif
 {/* zName:     */ "hard_heap_limit",
  /* ePragTyp:  */ PragTyp_HARD_HEAP_LIMIT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },












#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_CHECK)
 {/* zName:     */ "ignore_check_constraints",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_IgnoreChecks },
122833
122834
122835
122836
122837
122838
122839
122840
122841
122842
122843
122844
122845
122846
122847
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 15, 3,
  /* iArg:      */ 0 },
 {/* zName:     */ "index_list",
  /* ePragTyp:  */ PragTyp_INDEX_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 26, 5,
  /* iArg:      */ 0 },
 {/* zName:     */ "index_xinfo",
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 15, 6,
  /* iArg:      */ 1 },
#endif







|







124165
124166
124167
124168
124169
124170
124171
124172
124173
124174
124175
124176
124177
124178
124179
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 15, 3,
  /* iArg:      */ 0 },
 {/* zName:     */ "index_list",
  /* ePragTyp:  */ PragTyp_INDEX_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 32, 5,
  /* iArg:      */ 0 },
 {/* zName:     */ "index_xinfo",
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 15, 6,
  /* iArg:      */ 1 },
#endif
122860
122861
122862
122863
122864
122865
122866
122867
122868
122869
122870
122871
122872
122873
122874
122875
122876
122877
122878
122879
122880
122881
122882
122883
122884
122885
122886
122887
122888
122889
122890
122891
122892
122893
122894
122895
122896
122897
122898
122899
  /* iArg:      */ 0 },
 {/* zName:     */ "journal_size_limit",
  /* ePragTyp:  */ PragTyp_JOURNAL_SIZE_LIMIT,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if defined(SQLITE_HAS_CODEC)
 {/* zName:     */ "key",
  /* ePragTyp:  */ PragTyp_KEY,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "legacy_alter_table",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_LegacyAlter },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
 {/* zName:     */ "lock_proxy_file",
  /* ePragTyp:  */ PragTyp_LOCK_PROXY_FILE,
  /* ePragFlg:  */ PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
 {/* zName:     */ "lock_status",
  /* ePragTyp:  */ PragTyp_LOCK_STATUS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 43, 2,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "locking_mode",
  /* ePragTyp:  */ PragTyp_LOCKING_MODE,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,







<
<
<
<
<
<
<


















|







124192
124193
124194
124195
124196
124197
124198







124199
124200
124201
124202
124203
124204
124205
124206
124207
124208
124209
124210
124211
124212
124213
124214
124215
124216
124217
124218
124219
124220
124221
124222
124223
124224
  /* iArg:      */ 0 },
 {/* zName:     */ "journal_size_limit",
  /* ePragTyp:  */ PragTyp_JOURNAL_SIZE_LIMIT,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif







#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "legacy_alter_table",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_LegacyAlter },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
 {/* zName:     */ "lock_proxy_file",
  /* ePragTyp:  */ PragTyp_LOCK_PROXY_FILE,
  /* ePragFlg:  */ PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
 {/* zName:     */ "lock_status",
  /* ePragTyp:  */ PragTyp_LOCK_STATUS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 47, 2,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "locking_mode",
  /* ePragTyp:  */ PragTyp_LOCKING_MODE,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
122974
122975
122976
122977
122978
122979
122980
122981
122982
122983
122984
122985
122986
122987
122988
122989
122990
122991
122992
122993
122994
122995
122996
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_ReadUncommit },
 {/* zName:     */ "recursive_triggers",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_RecTriggers },
#endif
#if defined(SQLITE_HAS_CODEC)
 {/* zName:     */ "rekey",
  /* ePragTyp:  */ PragTyp_KEY,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 1 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "reverse_unordered_selects",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_ReverseOrder },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)







<
<
<
<
<
<
<
<
<







124299
124300
124301
124302
124303
124304
124305









124306
124307
124308
124309
124310
124311
124312
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_ReadUncommit },
 {/* zName:     */ "recursive_triggers",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_RecTriggers },









 {/* zName:     */ "reverse_unordered_selects",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_ReverseOrder },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
123033
123034
123035
123036
123037
123038
123039
123040
123041
123042
123043
123044
123045
123046
123047
  /* iArg:      */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
 {/* zName:     */ "stats",
  /* ePragTyp:  */ PragTyp_STATS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 21, 5,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "synchronous",
  /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,







|







124349
124350
124351
124352
124353
124354
124355
124356
124357
124358
124359
124360
124361
124362
124363
  /* iArg:      */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
 {/* zName:     */ "stats",
  /* ePragTyp:  */ PragTyp_STATS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 27, 5,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "synchronous",
  /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
123067
123068
123069
123070
123071
123072
123073
123074
123075
123076
123077
123078
123079
123080
123081
123082
123083
123084
123085
123086
123087
123088
123089
123090







123091
123092
123093
123094
123095
123096
123097
  /* iArg:      */ 0 },
 {/* zName:     */ "temp_store_directory",
  /* ePragTyp:  */ PragTyp_TEMP_STORE_DIRECTORY,
  /* ePragFlg:  */ PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if defined(SQLITE_HAS_CODEC)
 {/* zName:     */ "textkey",
  /* ePragTyp:  */ PragTyp_KEY,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 4 },
 {/* zName:     */ "textrekey",
  /* ePragTyp:  */ PragTyp_KEY,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 5 },
#endif
 {/* zName:     */ "threads",
  /* ePragTyp:  */ PragTyp_THREADS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },







#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
 {/* zName:     */ "user_version",
  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_USER_VERSION },
#endif







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





>
>
>
>
>
>
>







124383
124384
124385
124386
124387
124388
124389












124390
124391
124392
124393
124394
124395
124396
124397
124398
124399
124400
124401
124402
124403
124404
124405
124406
124407
124408
  /* iArg:      */ 0 },
 {/* zName:     */ "temp_store_directory",
  /* ePragTyp:  */ PragTyp_TEMP_STORE_DIRECTORY,
  /* ePragFlg:  */ PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif












 {/* zName:     */ "threads",
  /* ePragTyp:  */ PragTyp_THREADS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "trusted_schema",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_TrustedSchema },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
 {/* zName:     */ "user_version",
  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_USER_VERSION },
#endif
123129
123130
123131
123132
123133
123134
123135
123136
123137
123138
123139
123140
123141
123142
123143
123144
123145
123146
123147
123148
123149
123150
123151
123152
123153
123154
  /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "wal_checkpoint",
  /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
  /* ePragFlg:  */ PragFlg_NeedSchema,
  /* ColNames:  */ 38, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "writable_schema",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
/* Number of pragmas: 65 on by default, 81 total. */

/************** End of pragma.h **********************************************/
/************** Continuing where we left off in pragma.c *********************/

/*
** Interpret the given string as a safety level.  Return 0 for OFF,
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or 







|










|







124440
124441
124442
124443
124444
124445
124446
124447
124448
124449
124450
124451
124452
124453
124454
124455
124456
124457
124458
124459
124460
124461
124462
124463
124464
124465
  /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "wal_checkpoint",
  /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
  /* ePragFlg:  */ PragFlg_NeedSchema,
  /* ColNames:  */ 44, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "writable_schema",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
/* Number of pragmas: 66 on by default, 76 total. */

/************** End of pragma.h **********************************************/
/************** Continuing where we left off in pragma.c *********************/

/*
** Interpret the given string as a safety level.  Return 0 for OFF,
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or 
123409
123410
123411
123412
123413
123414
123415

















































123416
123417
123418
123419
123420
123421
123422
      upr = mid - 1;
    }else{
      lwr = mid + 1;
    }
  }
  return lwr>upr ? 0 : &aPragmaName[mid];
}


















































/*
** Helper subroutine for PRAGMA integrity_check:
**
** Generate code to output a single-column result row with a value of the
** string held in register 3.  Decrement the result count in register 1
** and halt if the maximum number of result rows have been issued.







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







124720
124721
124722
124723
124724
124725
124726
124727
124728
124729
124730
124731
124732
124733
124734
124735
124736
124737
124738
124739
124740
124741
124742
124743
124744
124745
124746
124747
124748
124749
124750
124751
124752
124753
124754
124755
124756
124757
124758
124759
124760
124761
124762
124763
124764
124765
124766
124767
124768
124769
124770
124771
124772
124773
124774
124775
124776
124777
124778
124779
124780
124781
124782
      upr = mid - 1;
    }else{
      lwr = mid + 1;
    }
  }
  return lwr>upr ? 0 : &aPragmaName[mid];
}

/*
** Create zero or more entries in the output for the SQL functions
** defined by FuncDef p.
*/
static void pragmaFunclistLine(
  Vdbe *v,               /* The prepared statement being created */
  FuncDef *p,            /* A particular function definition */
  int isBuiltin,         /* True if this is a built-in function */
  int showInternFuncs    /* True if showing internal functions */
){
  for(; p; p=p->pNext){
    const char *zType;
    static const u32 mask = 
        SQLITE_DETERMINISTIC |
        SQLITE_DIRECTONLY |
        SQLITE_SUBTYPE |
        SQLITE_INNOCUOUS |
        SQLITE_FUNC_INTERNAL
    ;
    static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" };

    assert( SQLITE_FUNC_ENCMASK==0x3 );
    assert( strcmp(azEnc[SQLITE_UTF8],"utf8")==0 );
    assert( strcmp(azEnc[SQLITE_UTF16LE],"utf16le")==0 );
    assert( strcmp(azEnc[SQLITE_UTF16BE],"utf16be")==0 );

    if( p->xSFunc==0 ) continue;
    if( (p->funcFlags & SQLITE_FUNC_INTERNAL)!=0
     && showInternFuncs==0
    ){
      continue;
    }    
    if( p->xValue!=0 ){
      zType = "w";
    }else if( p->xFinalize!=0 ){
      zType = "a";
    }else{
      zType = "s";
    }
    sqlite3VdbeMultiLoad(v, 1, "sissii",
       p->zName, isBuiltin,
       zType, azEnc[p->funcFlags&SQLITE_FUNC_ENCMASK],
       p->nArg,
       (p->funcFlags & mask) ^ SQLITE_INNOCUOUS
    );
  }
}


/*
** Helper subroutine for PRAGMA integrity_check:
**
** Generate code to output a single-column result row with a value of the
** string held in register 3.  Decrement the result count in register 1
** and halt if the maximum number of result rows have been issued.
124374
124375
124376
124377
124378
124379
124380

124381
124382
124383
124384
124385
124386
124387
124388
124389
124390
124391
124392
124393
124394
124395
124396
124397
  break;

#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
  case PragTyp_FUNCTION_LIST: {
    int i;
    HashElem *j;
    FuncDef *p;

    pParse->nMem = 2;
    for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
      for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
        if( p->funcFlags & SQLITE_FUNC_INTERNAL ) continue;
        sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1);
      }
    }
    for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
      p = (FuncDef*)sqliteHashData(j);
      sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0);
    }
  }
  break;

#ifndef SQLITE_OMIT_VIRTUALTABLE
  case PragTyp_MODULE_LIST: {
    HashElem *j;







>
|


<
|




|







125734
125735
125736
125737
125738
125739
125740
125741
125742
125743
125744

125745
125746
125747
125748
125749
125750
125751
125752
125753
125754
125755
125756
125757
  break;

#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
  case PragTyp_FUNCTION_LIST: {
    int i;
    HashElem *j;
    FuncDef *p;
    int showInternFunc = (db->mDbFlags & DBFLAG_InternalFunc)!=0;
    pParse->nMem = 6;
    for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
      for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){

        pragmaFunclistLine(v, p, 1, showInternFunc);
      }
    }
    for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
      p = (FuncDef*)sqliteHashData(j);
      pragmaFunclistLine(v, p, 0, showInternFunc);
    }
  }
  break;

#ifndef SQLITE_OMIT_VIRTUALTABLE
  case PragTyp_MODULE_LIST: {
    HashElem *j;
124711
124712
124713
124714
124715
124716
124717

124718

124719
124720
124721
124722
124723
124724
124725
        /* Verify that all NOT NULL columns really are NOT NULL */
        for(j=0; j<pTab->nCol; j++){
          char *zErr;
          int jmp2;
          if( j==pTab->iPKey ) continue;
          if( pTab->aCol[j].notNull==0 ) continue;
          sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);

          sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);

          jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
          zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
                              pTab->aCol[j].zName);
          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
          integrityCheckResultRow(v);
          sqlite3VdbeJumpHere(v, jmp2);
        }







>
|
>







126071
126072
126073
126074
126075
126076
126077
126078
126079
126080
126081
126082
126083
126084
126085
126086
126087
        /* Verify that all NOT NULL columns really are NOT NULL */
        for(j=0; j<pTab->nCol; j++){
          char *zErr;
          int jmp2;
          if( j==pTab->iPKey ) continue;
          if( pTab->aCol[j].notNull==0 ) continue;
          sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
          if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
            sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
          }
          jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
          zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
                              pTab->aCol[j].zName);
          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
          integrityCheckResultRow(v);
          sqlite3VdbeJumpHere(v, jmp2);
        }
124888
124889
124890
124891
124892
124893
124894
124895
124896
124897
124898
124899
124900
124901
124902


124903
124904
124905
124906
124907
124908
124909
      returnSingleText(v, encnames[ENC(pParse->db)].zName);
    }else{                        /* "PRAGMA encoding = XXX" */
      /* Only change the value of sqlite.enc if the database handle is not
      ** initialized. If the main database exists, the new sqlite.enc value
      ** will be overwritten when the schema is next loaded. If it does not
      ** already exists, it will be created to use the new encoding value.
      */
      if( 
        !(DbHasProperty(db, 0, DB_SchemaLoaded)) || 
        DbHasProperty(db, 0, DB_Empty) 
      ){
        for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
          if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
            SCHEMA_ENC(db) = ENC(db) =
                pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;


            break;
          }
        }
        if( !pEnc->zName ){
          sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
        }
      }







|
<
<
<


<
|
>
>







126250
126251
126252
126253
126254
126255
126256
126257



126258
126259

126260
126261
126262
126263
126264
126265
126266
126267
126268
126269
      returnSingleText(v, encnames[ENC(pParse->db)].zName);
    }else{                        /* "PRAGMA encoding = XXX" */
      /* Only change the value of sqlite.enc if the database handle is not
      ** initialized. If the main database exists, the new sqlite.enc value
      ** will be overwritten when the schema is next loaded. If it does not
      ** already exists, it will be created to use the new encoding value.
      */
      if( (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){



        for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
          if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){

            u8 enc = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
            SCHEMA_ENC(db) = enc;
            sqlite3SetTextEncoding(db, enc);
            break;
          }
        }
        if( !pEnc->zName ){
          sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
        }
      }
125272
125273
125274
125275
125276
125277
125278
125279
125280
125281
125282
125283
125284
125285
125286
125287
125288
125289
125290
125291
125292
125293
125294
125295
125296
125297
125298
125299
125300
125301
125302
125303
125304
125305
125306
125307
125308
125309
125310
125311
125312
125313
125314
125315
125316
125317
125318
125319
125320
125321
125322
125323
125324
125325
125326
125327
125328
125329
125330
125331
125332
125333
125334
125335
125336
125337
125338
      }
      sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState);
    }
    break;
  }
#endif

#ifdef SQLITE_HAS_CODEC
  /* Pragma        iArg
  ** ----------   ------
  **  key           0
  **  rekey         1
  **  hexkey        2
  **  hexrekey      3
  **  textkey       4
  **  textrekey     5
  */
  case PragTyp_KEY: {
    if( zRight ){
      char zBuf[40];
      const char *zKey = zRight;
      int n;
      if( pPragma->iArg==2 || pPragma->iArg==3 ){
        u8 iByte;
        int i;
        for(i=0, iByte=0; i<sizeof(zBuf)*2 && sqlite3Isxdigit(zRight[i]); i++){
          iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
          if( (i&1)!=0 ) zBuf[i/2] = iByte;
        }
        zKey = zBuf;
        n = i/2;
      }else{
        n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1;
      }
      if( (pPragma->iArg & 1)==0 ){
        rc = sqlite3_key_v2(db, zDb, zKey, n);
      }else{
        rc = sqlite3_rekey_v2(db, zDb, zKey, n);
      }
      if( rc==SQLITE_OK && n!=0 ){
        sqlite3VdbeSetNumCols(v, 1);
        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC);
        returnSingleText(v, "ok");
      }
    }
    break;
  }
#endif
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
  case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){
#ifdef SQLITE_HAS_CODEC
    if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
      sqlite3_activate_see(&zRight[4]);
    }
#endif
#ifdef SQLITE_ENABLE_CEROD
    if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
      sqlite3_activate_cerod(&zRight[6]);
    }
#endif
  }
  break;
#endif

  } /* End of the PRAGMA switch */

  /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only







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

<
<
<
<
<
<



<







126632
126633
126634
126635
126636
126637
126638









































126639
126640






126641
126642
126643

126644
126645
126646
126647
126648
126649
126650
      }
      sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState);
    }
    break;
  }
#endif










































#if defined(SQLITE_ENABLE_CEROD)
  case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){






    if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
      sqlite3_activate_cerod(&zRight[6]);
    }

  }
  break;
#endif

  } /* End of the PRAGMA switch */

  /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only
125752
125753
125754
125755
125756
125757
125758
125759
125760
125761
125762
125763
125764
125765
125766
  InitData *pData = (InitData*)pInit;
  sqlite3 *db = pData->db;
  int iDb = pData->iDb;

  assert( argc==5 );
  UNUSED_PARAMETER2(NotUsed, argc);
  assert( sqlite3_mutex_held(db->mutex) );
  DbClearProperty(db, iDb, DB_Empty);
  pData->nInitRow++;
  if( db->mallocFailed ){
    corruptSchema(pData, argv[1], 0);
    return 1;
  }

  assert( iDb>=0 && iDb<db->nDb );







|







127064
127065
127066
127067
127068
127069
127070
127071
127072
127073
127074
127075
127076
127077
127078
  InitData *pData = (InitData*)pInit;
  sqlite3 *db = pData->db;
  int iDb = pData->iDb;

  assert( argc==5 );
  UNUSED_PARAMETER2(NotUsed, argc);
  assert( sqlite3_mutex_held(db->mutex) );
  db->mDbFlags |= DBFLAG_EncodingFixed;
  pData->nInitRow++;
  if( db->mallocFailed ){
    corruptSchema(pData, argv[1], 0);
    return 1;
  }

  assert( iDb>=0 && iDb<db->nDb );
125840
125841
125842
125843
125844
125845
125846

125847
125848
125849
125850
125851
125852
125853
#endif
  Db *pDb;
  char const *azArg[6];
  int meta[5];
  InitData initData;
  const char *zMasterName;
  int openedTransaction = 0;


  assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pSchema );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );








>







127152
127153
127154
127155
127156
127157
127158
127159
127160
127161
127162
127163
127164
127165
127166
#endif
  Db *pDb;
  char const *azArg[6];
  int meta[5];
  InitData initData;
  const char *zMasterName;
  int openedTransaction = 0;
  int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed);

  assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pSchema );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );

125868
125869
125870
125871
125872
125873
125874

125875
125876
125877
125878
125879
125880
125881
  initData.db = db;
  initData.iDb = iDb;
  initData.rc = SQLITE_OK;
  initData.pzErrMsg = pzErrMsg;
  initData.mInitFlags = mFlags;
  initData.nInitRow = 0;
  sqlite3InitCallback(&initData, 5, (char **)azArg, 0);

  if( initData.rc ){
    rc = initData.rc;
    goto error_out;
  }

  /* Create a cursor to hold the database open
  */







>







127181
127182
127183
127184
127185
127186
127187
127188
127189
127190
127191
127192
127193
127194
127195
  initData.db = db;
  initData.iDb = iDb;
  initData.rc = SQLITE_OK;
  initData.pzErrMsg = pzErrMsg;
  initData.mInitFlags = mFlags;
  initData.nInitRow = 0;
  sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
  db->mDbFlags &= mask;
  if( initData.rc ){
    rc = initData.rc;
    goto error_out;
  }

  /* Create a cursor to hold the database open
  */
125927
125928
125929
125930
125931
125932
125933
125934
125935
125936

125937
125938
125939
125940
125941
125942
125943

125944
125945
125946
125947
125948
125949
125950
125951
125952
125953
125954
125955
125956
125957
125958
125959
125960
125961

  /* If opening a non-empty database, check the text encoding. For the
  ** main database, set sqlite3.enc to the encoding of the main database.
  ** For an attached db, it is an error if the encoding is not the same
  ** as sqlite3.enc.
  */
  if( meta[BTREE_TEXT_ENCODING-1] ){  /* text encoding */
    if( iDb==0 ){
#ifndef SQLITE_OMIT_UTF16
      u8 encoding;

      /* If opening the main database, set ENC(db). */
      encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
      if( encoding==0 ) encoding = SQLITE_UTF8;
      ENC(db) = encoding;
#else
      ENC(db) = SQLITE_UTF8;
#endif

    }else{
      /* If opening an attached database, the encoding much match ENC(db) */
      if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
        sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
            " text encoding as main database");
        rc = SQLITE_ERROR;
        goto initone_error_out;
      }
    }
  }else{
    DbSetProperty(db, iDb, DB_Empty);
  }
  pDb->pSchema->enc = ENC(db);

  if( pDb->pSchema->cache_size==0 ){
#ifndef SQLITE_OMIT_DEPRECATED
    size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]);
    if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }







|
<

>



<

|

>


|






<
<







127241
127242
127243
127244
127245
127246
127247
127248

127249
127250
127251
127252
127253

127254
127255
127256
127257
127258
127259
127260
127261
127262
127263
127264
127265
127266


127267
127268
127269
127270
127271
127272
127273

  /* If opening a non-empty database, check the text encoding. For the
  ** main database, set sqlite3.enc to the encoding of the main database.
  ** For an attached db, it is an error if the encoding is not the same
  ** as sqlite3.enc.
  */
  if( meta[BTREE_TEXT_ENCODING-1] ){  /* text encoding */
    if( iDb==0 && (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){

      u8 encoding;
#ifndef SQLITE_OMIT_UTF16
      /* If opening the main database, set ENC(db). */
      encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
      if( encoding==0 ) encoding = SQLITE_UTF8;

#else
      encoding = SQLITE_UTF8;
#endif
      sqlite3SetTextEncoding(db, encoding);
    }else{
      /* If opening an attached database, the encoding much match ENC(db) */
      if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
        sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
            " text encoding as main database");
        rc = SQLITE_ERROR;
        goto initone_error_out;
      }
    }


  }
  pDb->pSchema->enc = ENC(db);

  if( pDb->pSchema->cache_size==0 ){
#ifndef SQLITE_OMIT_DEPRECATED
    size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]);
    if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
126059
126060
126061
126062
126063
126064
126065
126066
126067
126068
126069
126070
126071
126072
126073
126074
/*
** Initialize all database files - the main database file, the file
** used to store temporary tables, and any additional database files
** created using ATTACH statements.  Return a success code.  If an
** error occurs, write an error message into *pzErrMsg.
**
** After a database is initialized, the DB_SchemaLoaded bit is set
** bit is set in the flags field of the Db structure. If the database
** file was of zero-length, then the DB_Empty flag is also set.
*/
SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
  int i, rc;
  int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
  
  assert( sqlite3_mutex_held(db->mutex) );
  assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );







|
<







127371
127372
127373
127374
127375
127376
127377
127378

127379
127380
127381
127382
127383
127384
127385
/*
** Initialize all database files - the main database file, the file
** used to store temporary tables, and any additional database files
** created using ATTACH statements.  Return a success code.  If an
** error occurs, write an error message into *pzErrMsg.
**
** After a database is initialized, the DB_SchemaLoaded bit is set
** bit is set in the flags field of the Db structure. 

*/
SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
  int i, rc;
  int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
  
  assert( sqlite3_mutex_held(db->mutex) );
  assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
126677
126678
126679
126680
126681
126682
126683
126684



126685
126686
126687
126688
126689
126690
126691
126692
126693
126694
126695
126696
126697
126698
126699
126700
126701
126702
126703
126704
126705
126706
126707
#endif
  struct RowLoadInfo *pDeferredRowLoad;  /* Deferred row loading info or NULL */
};
#define SORTFLAG_UseSorter  0x01   /* Use SorterOpen instead of OpenEphemeral */

/*
** Delete all the content of a Select structure.  Deallocate the structure
** itself only if bFree is true.



*/
static void clearSelect(sqlite3 *db, Select *p, int bFree){
  while( p ){
    Select *pPrior = p->pPrior;
    sqlite3ExprListDelete(db, p->pEList);
    sqlite3SrcListDelete(db, p->pSrc);
    sqlite3ExprDelete(db, p->pWhere);
    sqlite3ExprListDelete(db, p->pGroupBy);
    sqlite3ExprDelete(db, p->pHaving);
    sqlite3ExprListDelete(db, p->pOrderBy);
    sqlite3ExprDelete(db, p->pLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
    if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
      sqlite3WindowListDelete(db, p->pWinDefn);
    }
    assert( p->pWin==0 );
#endif
    if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
    if( bFree ) sqlite3DbFreeNN(db, p);
    p = pPrior;
    bFree = 1;
  }
}







|
>
>
>















<







127988
127989
127990
127991
127992
127993
127994
127995
127996
127997
127998
127999
128000
128001
128002
128003
128004
128005
128006
128007
128008
128009
128010
128011
128012
128013

128014
128015
128016
128017
128018
128019
128020
#endif
  struct RowLoadInfo *pDeferredRowLoad;  /* Deferred row loading info or NULL */
};
#define SORTFLAG_UseSorter  0x01   /* Use SorterOpen instead of OpenEphemeral */

/*
** Delete all the content of a Select structure.  Deallocate the structure
** itself depending on the value of bFree
**
** If bFree==1, call sqlite3DbFree() on the p object.
** If bFree==0, Leave the first Select object unfreed
*/
static void clearSelect(sqlite3 *db, Select *p, int bFree){
  while( p ){
    Select *pPrior = p->pPrior;
    sqlite3ExprListDelete(db, p->pEList);
    sqlite3SrcListDelete(db, p->pSrc);
    sqlite3ExprDelete(db, p->pWhere);
    sqlite3ExprListDelete(db, p->pGroupBy);
    sqlite3ExprDelete(db, p->pHaving);
    sqlite3ExprListDelete(db, p->pOrderBy);
    sqlite3ExprDelete(db, p->pLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
    if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
      sqlite3WindowListDelete(db, p->pWinDefn);
    }

#endif
    if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
    if( bFree ) sqlite3DbFreeNN(db, p);
    p = pPrior;
    bFree = 1;
  }
}
126780
126781
126782
126783
126784
126785
126786















126787
126788
126789
126790
126791
126792
126793

/*
** Delete the given Select structure and all of its substructures.
*/
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
  if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
















/*
** Return a pointer to the right-most SELECT statement in a compound.
*/
static Select *findRightmost(Select *p){
  while( p->pNext ) p = p->pNext;
  return p;







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







128093
128094
128095
128096
128097
128098
128099
128100
128101
128102
128103
128104
128105
128106
128107
128108
128109
128110
128111
128112
128113
128114
128115
128116
128117
128118
128119
128120
128121

/*
** Delete the given Select structure and all of its substructures.
*/
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
  if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}

/*
** Delete all the substructure for p, but keep p allocated.  Redefine
** p to be a single SELECT where every column of the result set has a
** value of NULL.
*/
SQLITE_PRIVATE void sqlite3SelectReset(Parse *pParse, Select *p){
  if( ALWAYS(p) ){
    clearSelect(pParse->db, p, 0);
    memset(&p->iLimit, 0, sizeof(Select) - offsetof(Select,iLimit));
    p->pEList = sqlite3ExprListAppend(pParse, 0,
                     sqlite3ExprAlloc(pParse->db,TK_NULL,0,0));
    p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(SrcList));
  }
}

/*
** Return a pointer to the right-most SELECT statement in a compound.
*/
static Select *findRightmost(Select *p){
  while( p->pNext ) p = p->pNext;
  return p;
126889
126890
126891
126892
126893
126894
126895
126896

126897
126898
126899
126900
126901
126902
126903
126904


126905
126906
126907
126908
126909
126910
126911
** If not found, return FALSE.
*/
static int tableAndColumnIndex(
  SrcList *pSrc,       /* Array of tables to search */
  int N,               /* Number of tables in pSrc->a[] to search */
  const char *zCol,    /* Name of the column we are looking for */
  int *piTab,          /* Write index of pSrc->a[] here */
  int *piCol           /* Write index of pSrc->a[*piTab].pTab->aCol[] here */

){
  int i;               /* For looping over tables in pSrc */
  int iCol;            /* Index of column matching zCol */

  assert( (piTab==0)==(piCol==0) );  /* Both or neither are NULL */
  for(i=0; i<N; i++){
    iCol = columnIndex(pSrc->a[i].pTab, zCol);
    if( iCol>=0 ){


      if( piTab ){
        *piTab = i;
        *piCol = iCol;
      }
      return 1;
    }
  }







|
>







|
>
>







128217
128218
128219
128220
128221
128222
128223
128224
128225
128226
128227
128228
128229
128230
128231
128232
128233
128234
128235
128236
128237
128238
128239
128240
128241
128242
** If not found, return FALSE.
*/
static int tableAndColumnIndex(
  SrcList *pSrc,       /* Array of tables to search */
  int N,               /* Number of tables in pSrc->a[] to search */
  const char *zCol,    /* Name of the column we are looking for */
  int *piTab,          /* Write index of pSrc->a[] here */
  int *piCol,          /* Write index of pSrc->a[*piTab].pTab->aCol[] here */
  int bIgnoreHidden    /* True to ignore hidden columns */
){
  int i;               /* For looping over tables in pSrc */
  int iCol;            /* Index of column matching zCol */

  assert( (piTab==0)==(piCol==0) );  /* Both or neither are NULL */
  for(i=0; i<N; i++){
    iCol = columnIndex(pSrc->a[i].pTab, zCol);
    if( iCol>=0 
     && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
    ){
      if( piTab ){
        *piTab = i;
        *piCol = iCol;
      }
      return 1;
    }
  }
127062
127063
127064
127065
127066
127067
127068

127069
127070
127071
127072
127073
127074
127075
127076
127077
127078
127079
        return 1;
      }
      for(j=0; j<pRightTab->nCol; j++){
        char *zName;   /* Name of column in the right table */
        int iLeft;     /* Matching left table */
        int iLeftCol;  /* Matching column in the left table */


        zName = pRightTab->aCol[j].zName;
        if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){
          addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j,
                       isOuter, &p->pWhere);
        }
      }
    }

    /* Disallow both ON and USING clauses in the same join
    */
    if( pRight->pOn && pRight->pUsing ){







>

|

|







128393
128394
128395
128396
128397
128398
128399
128400
128401
128402
128403
128404
128405
128406
128407
128408
128409
128410
128411
        return 1;
      }
      for(j=0; j<pRightTab->nCol; j++){
        char *zName;   /* Name of column in the right table */
        int iLeft;     /* Matching left table */
        int iLeftCol;  /* Matching column in the left table */

        if( IsHiddenColumn(&pRightTab->aCol[j]) ) continue;
        zName = pRightTab->aCol[j].zName;
        if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){
          addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j,
                isOuter, &p->pWhere);
        }
      }
    }

    /* Disallow both ON and USING clauses in the same join
    */
    if( pRight->pOn && pRight->pUsing ){
127105
127106
127107
127108
127109
127110
127111
127112
127113
127114
127115
127116
127117
127118
127119
        int iLeft;       /* Table on the left with matching column name */
        int iLeftCol;    /* Column number of matching column on the left */
        int iRightCol;   /* Column number of matching column on the right */

        zName = pList->a[j].zName;
        iRightCol = columnIndex(pRightTab, zName);
        if( iRightCol<0
         || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol)
        ){
          sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
            "not present in both tables", zName);
          return 1;
        }
        addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol,
                     isOuter, &p->pWhere);







|







128437
128438
128439
128440
128441
128442
128443
128444
128445
128446
128447
128448
128449
128450
128451
        int iLeft;       /* Table on the left with matching column name */
        int iLeftCol;    /* Column number of matching column on the left */
        int iRightCol;   /* Column number of matching column on the right */

        zName = pList->a[j].zName;
        iRightCol = columnIndex(pRightTab, zName);
        if( iRightCol<0
         || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0)
        ){
          sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
            "not present in both tables", zName);
          return 1;
        }
        addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol,
                     isOuter, &p->pWhere);
127511
127512
127513
127514
127515
127516
127517
127518
127519
127520
127521
127522
127523
127524
127525
    pParse->nMem += nResultCol;
  }
  pDest->nSdst = nResultCol;
  regOrig = regResult = pDest->iSdst;
  if( srcTab>=0 ){
    for(i=0; i<nResultCol; i++){
      sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
      VdbeComment((v, "%s", p->pEList->a[i].zName));
    }
  }else if( eDest!=SRT_Exists ){
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
    ExprList *pExtra = 0;
#endif
    /* If the destination is an EXISTS(...) expression, the actual
    ** values returned by the SELECT are not required.







|







128843
128844
128845
128846
128847
128848
128849
128850
128851
128852
128853
128854
128855
128856
128857
    pParse->nMem += nResultCol;
  }
  pDest->nSdst = nResultCol;
  regOrig = regResult = pDest->iSdst;
  if( srcTab>=0 ){
    for(i=0; i<nResultCol; i++){
      sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
      VdbeComment((v, "%s", p->pEList->a[i].zEName));
    }
  }else if( eDest!=SRT_Exists ){
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
    ExprList *pExtra = 0;
#endif
    /* If the destination is an EXISTS(...) expression, the actual
    ** values returned by the SELECT are not required.
128132
128133
128134
128135
128136
128137
128138
128139
128140
128141
128142
128143
128144
128145
128146
      int iRead;
      if( aOutEx[i].u.x.iOrderByCol ){
        iRead = aOutEx[i].u.x.iOrderByCol-1;
      }else{
        iRead = iCol--;
      }
      sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i);
      VdbeComment((v, "%s", aOutEx[i].zName?aOutEx[i].zName : aOutEx[i].zSpan));
    }
  }
  switch( eDest ){
    case SRT_Table:
    case SRT_EphemTab: {
      sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq, regRow);
      sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);







|







129464
129465
129466
129467
129468
129469
129470
129471
129472
129473
129474
129475
129476
129477
129478
      int iRead;
      if( aOutEx[i].u.x.iOrderByCol ){
        iRead = aOutEx[i].u.x.iOrderByCol-1;
      }else{
        iRead = iCol--;
      }
      sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i);
      VdbeComment((v, "%s", aOutEx[i].zEName));
    }
  }
  switch( eDest ){
    case SRT_Table:
    case SRT_EphemTab: {
      sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq, regRow);
      sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
128466
128467
128468
128469
128470
128471
128472
128473
128474
128475
128476
128477
128478
128479
128480
128481
128482
  sqlite3VdbeSetNumCols(v, pEList->nExpr);
  for(i=0; i<pEList->nExpr; i++){
    Expr *p = pEList->a[i].pExpr;

    assert( p!=0 );
    assert( p->op!=TK_AGG_COLUMN );  /* Agg processing has not run yet */
    assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */
    if( pEList->a[i].zName ){
      /* An AS clause always takes first priority */
      char *zName = pEList->a[i].zName;
      sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
    }else if( srcName && p->op==TK_COLUMN ){
      char *zCol;
      int iCol = p->iColumn;
      pTab = p->y.pTab;
      assert( pTab!=0 );
      if( iCol<0 ) iCol = pTab->iPKey;







|

|







129798
129799
129800
129801
129802
129803
129804
129805
129806
129807
129808
129809
129810
129811
129812
129813
129814
  sqlite3VdbeSetNumCols(v, pEList->nExpr);
  for(i=0; i<pEList->nExpr; i++){
    Expr *p = pEList->a[i].pExpr;

    assert( p!=0 );
    assert( p->op!=TK_AGG_COLUMN );  /* Agg processing has not run yet */
    assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */
    if( pEList->a[i].zEName && pEList->a[i].eEName==ENAME_NAME ){
      /* An AS clause always takes first priority */
      char *zName = pEList->a[i].zEName;
      sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
    }else if( srcName && p->op==TK_COLUMN ){
      char *zCol;
      int iCol = p->iColumn;
      pTab = p->y.pTab;
      assert( pTab!=0 );
      if( iCol<0 ) iCol = pTab->iPKey;
128490
128491
128492
128493
128494
128495
128496
128497
128498
128499
128500
128501
128502
128503
128504
        char *zName = 0;
        zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol);
        sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC);
      }else{
        sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT);
      }
    }else{
      const char *z = pEList->a[i].zSpan;
      z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z);
      sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC);
    }
  }
  generateColumnTypes(pParse, pTabList, pEList);
}








|







129822
129823
129824
129825
129826
129827
129828
129829
129830
129831
129832
129833
129834
129835
129836
        char *zName = 0;
        zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol);
        sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC);
      }else{
        sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT);
      }
    }else{
      const char *z = pEList->a[i].zEName;
      z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z);
      sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC);
    }
  }
  generateColumnTypes(pParse, pTabList, pEList);
}

128552
128553
128554
128555
128556
128557
128558
128559
128560
128561
128562
128563
128564
128565
128566
128567
128568
128569
128570
128571
128572
128573
128574
128575
128576
128577
128578
128579
128580
128581
128582
128583
128584
128585
128586
128587
128588
128589
128590
128591
128592
128593
128594
128595
128596
128597
128598
128599
128600
128601

128602
128603
128604
128605
128606
128607
128608
  assert( nCol==(i16)nCol );
  *pnCol = nCol;
  *paCol = aCol;

  for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
    /* Get an appropriate name for the column
    */
    if( (zName = pEList->a[i].zName)!=0 ){
      /* If the column contains an "AS <name>" phrase, use <name> as the name */
    }else{
      Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
      while( pColExpr->op==TK_DOT ){
        pColExpr = pColExpr->pRight;
        assert( pColExpr!=0 );
      }
      if( pColExpr->op==TK_COLUMN ){
        /* For columns use the column name name */
        int iCol = pColExpr->iColumn;
        Table *pTab = pColExpr->y.pTab;
        assert( pTab!=0 );
        if( iCol<0 ) iCol = pTab->iPKey;
        zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
      }else if( pColExpr->op==TK_ID ){
        assert( !ExprHasProperty(pColExpr, EP_IntValue) );
        zName = pColExpr->u.zToken;
      }else{
        /* Use the original text of the column expression as its name */
        zName = pEList->a[i].zSpan;
      }
    }
    if( zName ){
      zName = sqlite3DbStrDup(db, zName);
    }else{
      zName = sqlite3MPrintf(db,"column%d",i+1);
    }

    /* Make sure the column name is unique.  If the name is not unique,
    ** append an integer to the name so that it becomes unique.
    */
    cnt = 0;
    while( zName && sqlite3HashFind(&ht, zName)!=0 ){
      nName = sqlite3Strlen30(zName);
      if( nName>0 ){
        for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
        if( zName[j]==':' ) nName = j;
      }
      zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
      if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
    }
    pCol->zName = zName;

    sqlite3ColumnPropertiesFromName(0, pCol);
    if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
      sqlite3OomFault(db);
    }
  }
  sqlite3HashClear(&ht);
  if( db->mallocFailed ){







|



















|


|



















>







129884
129885
129886
129887
129888
129889
129890
129891
129892
129893
129894
129895
129896
129897
129898
129899
129900
129901
129902
129903
129904
129905
129906
129907
129908
129909
129910
129911
129912
129913
129914
129915
129916
129917
129918
129919
129920
129921
129922
129923
129924
129925
129926
129927
129928
129929
129930
129931
129932
129933
129934
129935
129936
129937
129938
129939
129940
129941
  assert( nCol==(i16)nCol );
  *pnCol = nCol;
  *paCol = aCol;

  for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
    /* Get an appropriate name for the column
    */
    if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){
      /* If the column contains an "AS <name>" phrase, use <name> as the name */
    }else{
      Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
      while( pColExpr->op==TK_DOT ){
        pColExpr = pColExpr->pRight;
        assert( pColExpr!=0 );
      }
      if( pColExpr->op==TK_COLUMN ){
        /* For columns use the column name name */
        int iCol = pColExpr->iColumn;
        Table *pTab = pColExpr->y.pTab;
        assert( pTab!=0 );
        if( iCol<0 ) iCol = pTab->iPKey;
        zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
      }else if( pColExpr->op==TK_ID ){
        assert( !ExprHasProperty(pColExpr, EP_IntValue) );
        zName = pColExpr->u.zToken;
      }else{
        /* Use the original text of the column expression as its name */
        zName = pEList->a[i].zEName;
      }
    }
    if( zName && !sqlite3IsTrueOrFalse(zName) ){
      zName = sqlite3DbStrDup(db, zName);
    }else{
      zName = sqlite3MPrintf(db,"column%d",i+1);
    }

    /* Make sure the column name is unique.  If the name is not unique,
    ** append an integer to the name so that it becomes unique.
    */
    cnt = 0;
    while( zName && sqlite3HashFind(&ht, zName)!=0 ){
      nName = sqlite3Strlen30(zName);
      if( nName>0 ){
        for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
        if( zName[j]==':' ) nName = j;
      }
      zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
      if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
    }
    pCol->zName = zName;
    pCol->hName = sqlite3StrIHash(zName);
    sqlite3ColumnPropertiesFromName(0, pCol);
    if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
      sqlite3OomFault(db);
    }
  }
  sqlite3HashClear(&ht);
  if( db->mallocFailed ){
129067
129068
129069
129070
129071
129072
129073



129074
129075
129076
129077
129078
129079
129080
  int rc = 0;
  int bShowAll = p->pLimit==0;
  assert( p->selFlags & SF_MultiValue );
  do{
    assert( p->selFlags & SF_Values );
    assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
    assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );



    if( p->pPrior==0 ) break;
    assert( p->pPrior->pNext==p );
    p = p->pPrior;
    nRow += bShowAll;
  }while(1);
  ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow,
                    nRow==1 ? "" : "S"));







>
>
>







130400
130401
130402
130403
130404
130405
130406
130407
130408
130409
130410
130411
130412
130413
130414
130415
130416
  int rc = 0;
  int bShowAll = p->pLimit==0;
  assert( p->selFlags & SF_MultiValue );
  do{
    assert( p->selFlags & SF_Values );
    assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
    assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
#ifndef SQLITE_OMIT_WINDOWFUNC
    if( p->pWin ) return -1;
#endif
    if( p->pPrior==0 ) break;
    assert( p->pPrior->pNext==p );
    p = p->pPrior;
    nRow += bShowAll;
  }while(1);
  ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow,
                    nRow==1 ? "" : "S"));
129157
129158
129159
129160
129161
129162
129163
129164

129165
129166
129167
129168
129169
129170
129171
    dest.eDest = SRT_Table;
  }

  /* Special handling for a compound-select that originates as a VALUES clause.
  */
  if( p->selFlags & SF_MultiValue ){
    rc = multiSelectValues(pParse, p, &dest);
    goto multi_select_end;

  }

  /* Make sure all SELECTs in the statement have the same number of elements
  ** in their result sets.
  */
  assert( p->pEList && pPrior->pEList );
  assert( p->pEList->nExpr==pPrior->pEList->nExpr );







|
>







130493
130494
130495
130496
130497
130498
130499
130500
130501
130502
130503
130504
130505
130506
130507
130508
    dest.eDest = SRT_Table;
  }

  /* Special handling for a compound-select that originates as a VALUES clause.
  */
  if( p->selFlags & SF_MultiValue ){
    rc = multiSelectValues(pParse, p, &dest);
    if( rc>=0 ) goto multi_select_end;
    rc = SQLITE_OK;
  }

  /* Make sure all SELECTs in the statement have the same number of elements
  ** in their result sets.
  */
  assert( p->pEList && pPrior->pEList );
  assert( p->pEList->nExpr==pPrior->pEList->nExpr );
129302
129303
129304
129305
129306
129307
129308

129309
129310
129311
129312
129313
129314
129315
129316
129317
129318
        p->iLimit = 0;
        p->iOffset = 0;
  
        /* Convert the data in the temporary table into whatever form
        ** it is that we currently need.
        */
        assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );

        if( dest.eDest!=priorOp ){
          int iCont, iBreak, iStart;
          assert( p->pEList );
          iBreak = sqlite3VdbeMakeLabel(pParse);
          iCont = sqlite3VdbeMakeLabel(pParse);
          computeLimitRegisters(pParse, p, iBreak);
          sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
          iStart = sqlite3VdbeCurrentAddr(v);
          selectInnerLoop(pParse, p, unionTab,
                          0, 0, &dest, iCont, iBreak);







>
|

<







130639
130640
130641
130642
130643
130644
130645
130646
130647
130648

130649
130650
130651
130652
130653
130654
130655
        p->iLimit = 0;
        p->iOffset = 0;
  
        /* Convert the data in the temporary table into whatever form
        ** it is that we currently need.
        */
        assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
        assert( p->pEList || db->mallocFailed );
        if( dest.eDest!=priorOp && db->mallocFailed==0 ){
          int iCont, iBreak, iStart;

          iBreak = sqlite3VdbeMakeLabel(pParse);
          iCont = sqlite3VdbeMakeLabel(pParse);
          computeLimitRegisters(pParse, p, iBreak);
          sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
          iStart = sqlite3VdbeCurrentAddr(v);
          selectInnerLoop(pParse, p, unionTab,
                          0, 0, &dest, iCont, iBreak);
129373
129374
129375
129376
129377
129378
129379

129380
129381
129382
129383
129384
129385
129386
        }
        sqlite3ExprDelete(db, p->pLimit);
        p->pLimit = pLimit;
  
        /* Generate code to take the intersection of the two temporary
        ** tables.
        */

        assert( p->pEList );
        iBreak = sqlite3VdbeMakeLabel(pParse);
        iCont = sqlite3VdbeMakeLabel(pParse);
        computeLimitRegisters(pParse, p, iBreak);
        sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
        r1 = sqlite3GetTempReg(pParse);
        iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);







>







130710
130711
130712
130713
130714
130715
130716
130717
130718
130719
130720
130721
130722
130723
130724
        }
        sqlite3ExprDelete(db, p->pLimit);
        p->pLimit = pLimit;
  
        /* Generate code to take the intersection of the two temporary
        ** tables.
        */
        if( rc ) break;
        assert( p->pEList );
        iBreak = sqlite3VdbeMakeLabel(pParse);
        iCont = sqlite3VdbeMakeLabel(pParse);
        computeLimitRegisters(pParse, p, iBreak);
        sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
        r1 = sqlite3GetTempReg(pParse);
        iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
129400
129401
129402
129403
129404
129405
129406

129407
129408
129409
129410
129411
129412
129413
  
  #ifndef SQLITE_OMIT_EXPLAIN
    if( p->pNext==0 ){
      ExplainQueryPlanPop(pParse);
    }
  #endif
  }

  
  /* Compute collating sequences used by 
  ** temporary tables needed to implement the compound select.
  ** Attach the KeyInfo structure to all temporary tables.
  **
  ** This section is run by the right-most SELECT statement only.
  ** SELECT statements to the left always skip this part.  The right-most







>







130738
130739
130740
130741
130742
130743
130744
130745
130746
130747
130748
130749
130750
130751
130752
  
  #ifndef SQLITE_OMIT_EXPLAIN
    if( p->pNext==0 ){
      ExplainQueryPlanPop(pParse);
    }
  #endif
  }
  if( pParse->nErr ) goto multi_select_end;
  
  /* Compute collating sequences used by 
  ** temporary tables needed to implement the compound select.
  ** Attach the KeyInfo structure to all temporary tables.
  **
  ** This section is run by the right-most SELECT statement only.
  ** SELECT statements to the left always skip this part.  The right-most
130042
130043
130044
130045
130046
130047
130048
130049



130050
130051
130052
130053
130054
130055
130056
){
  if( pExpr==0 ) return 0;
  if( ExprHasProperty(pExpr, EP_FromJoin)
   && pExpr->iRightJoinTable==pSubst->iTable
  ){
    pExpr->iRightJoinTable = pSubst->iNewTable;
  }
  if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){



    if( pExpr->iColumn<0 ){
      pExpr->op = TK_NULL;
    }else{
      Expr *pNew;
      Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
      Expr ifNullRow;
      assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );







|
>
>
>







131381
131382
131383
131384
131385
131386
131387
131388
131389
131390
131391
131392
131393
131394
131395
131396
131397
131398
){
  if( pExpr==0 ) return 0;
  if( ExprHasProperty(pExpr, EP_FromJoin)
   && pExpr->iRightJoinTable==pSubst->iTable
  ){
    pExpr->iRightJoinTable = pSubst->iNewTable;
  }
  if( pExpr->op==TK_COLUMN
   && pExpr->iTable==pSubst->iTable
   && !ExprHasProperty(pExpr, EP_FixedCol)
  ){
    if( pExpr->iColumn<0 ){
      pExpr->op = TK_NULL;
    }else{
      Expr *pNew;
      Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
      Expr ifNullRow;
      assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
130146
130147
130148
130149
130150
130151
130152
































130153
130154
130155
130156
130157
130158
130159
        substExprList(pSubst, pItem->u1.pFuncArg);
      }
    }
  }while( doPrior && (p = p->pPrior)!=0 );
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */

































#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
** This routine attempts to flatten subqueries as a performance optimization.
** This routine returns 1 if it makes changes and 0 if no flattening occurs.
**
** To understand the concept of flattening, consider the following
** query:







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







131488
131489
131490
131491
131492
131493
131494
131495
131496
131497
131498
131499
131500
131501
131502
131503
131504
131505
131506
131507
131508
131509
131510
131511
131512
131513
131514
131515
131516
131517
131518
131519
131520
131521
131522
131523
131524
131525
131526
131527
131528
131529
131530
131531
131532
131533
        substExprList(pSubst, pItem->u1.pFuncArg);
      }
    }
  }while( doPrior && (p = p->pPrior)!=0 );
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */

#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
** pSelect is a SELECT statement and pSrcItem is one item in the FROM
** clause of that SELECT.
**
** This routine scans the entire SELECT statement and recomputes the
** pSrcItem->colUsed mask.
*/
static int recomputeColumnsUsedExpr(Walker *pWalker, Expr *pExpr){
  struct SrcList_item *pItem;
  if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
  pItem = pWalker->u.pSrcItem;
  if( pItem->iCursor!=pExpr->iTable ) return WRC_Continue;
  if( pExpr->iColumn<0 ) return WRC_Continue;
  pItem->colUsed |= sqlite3ExprColUsed(pExpr);
  return WRC_Continue;
}
static void recomputeColumnsUsed(
  Select *pSelect,                 /* The complete SELECT statement */
  struct SrcList_item *pSrcItem    /* Which FROM clause item to recompute */
){
  Walker w;
  if( NEVER(pSrcItem->pTab==0) ) return;
  memset(&w, 0, sizeof(w));
  w.xExprCallback = recomputeColumnsUsedExpr;
  w.xSelectCallback = sqlite3SelectWalkNoop;
  w.u.pSrcItem = pSrcItem;
  pSrcItem->colUsed = 0;
  sqlite3WalkSelect(&w, pSelect);
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */

#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
** This routine attempts to flatten subqueries as a performance optimization.
** This routine returns 1 if it makes changes and 0 if no flattening occurs.
**
** To understand the concept of flattening, consider the following
** query:
130191
130192
130193
130194
130195
130196
130197

130198
130199
130200
130201
130202
130203
130204
**             from 2015-02-09.)
**
**   (3)  If the subquery is the right operand of a LEFT JOIN then
**        (3a) the subquery may not be a join and
**        (3b) the FROM clause of the subquery may not contain a virtual
**             table and
**        (3c) the outer query may not be an aggregate.

**
**   (4)  The subquery can not be DISTINCT.
**
**  (**)  At one point restrictions (4) and (5) defined a subset of DISTINCT
**        sub-queries that were excluded from this optimization. Restriction 
**        (4) has since been expanded to exclude all DISTINCT subqueries.
**







>







131565
131566
131567
131568
131569
131570
131571
131572
131573
131574
131575
131576
131577
131578
131579
**             from 2015-02-09.)
**
**   (3)  If the subquery is the right operand of a LEFT JOIN then
**        (3a) the subquery may not be a join and
**        (3b) the FROM clause of the subquery may not contain a virtual
**             table and
**        (3c) the outer query may not be an aggregate.
**        (3d) the outer query may not be DISTINCT.
**
**   (4)  The subquery can not be DISTINCT.
**
**  (**)  At one point restrictions (4) and (5) defined a subset of DISTINCT
**        sub-queries that were excluded from this optimization. Restriction 
**        (4) has since been expanded to exclude all DISTINCT subqueries.
**
130241
130242
130243
130244
130245
130246
130247

130248
130249
130250
130251
130252
130253
130254
**        (17b) no terms within the subquery compound may be aggregate
**              or DISTINCT, and
**        (17c) every term within the subquery compound must have a FROM clause
**        (17d) the outer query may not be
**              (17d1) aggregate, or
**              (17d2) DISTINCT, or
**              (17d3) a join.

**
**        The parent and sub-query may contain WHERE clauses. Subject to
**        rules (11), (13) and (14), they may also contain ORDER BY,
**        LIMIT and OFFSET clauses.  The subquery cannot use any compound
**        operator other than UNION ALL because all the other compound
**        operators have an implied DISTINCT which is disallowed by
**        restriction (4).







>







131616
131617
131618
131619
131620
131621
131622
131623
131624
131625
131626
131627
131628
131629
131630
**        (17b) no terms within the subquery compound may be aggregate
**              or DISTINCT, and
**        (17c) every term within the subquery compound must have a FROM clause
**        (17d) the outer query may not be
**              (17d1) aggregate, or
**              (17d2) DISTINCT, or
**              (17d3) a join.
**        (17e) the subquery may not contain window functions
**
**        The parent and sub-query may contain WHERE clauses. Subject to
**        rules (11), (13) and (14), they may also contain ORDER BY,
**        LIMIT and OFFSET clauses.  The subquery cannot use any compound
**        operator other than UNION ALL because all the other compound
**        operators have an implied DISTINCT which is disallowed by
**        restriction (4).
130387
130388
130389
130390
130391
130392
130393


130394
130395


130396
130397
130398
130399
130400
130401
130402
  ** aggregates are processed - there is no mechanism to determine if
  ** the LEFT JOIN table should be all-NULL.
  **
  ** See also tickets #306, #350, and #3300.
  */
  if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
    isLeftJoin = 1;


    if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
      /*  (3a)             (3c)     (3b) */


      return 0;
    }
  }
#ifdef SQLITE_EXTRA_IFNULLROW
  else if( iFrom>0 && !isAgg ){
    /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for
    ** every reference to any result column from subquery in a join, even







>
>
|
<
>
>







131763
131764
131765
131766
131767
131768
131769
131770
131771
131772

131773
131774
131775
131776
131777
131778
131779
131780
131781
  ** aggregates are processed - there is no mechanism to determine if
  ** the LEFT JOIN table should be all-NULL.
  **
  ** See also tickets #306, #350, and #3300.
  */
  if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
    isLeftJoin = 1;
    if( pSubSrc->nSrc>1                   /* (3a) */
     || isAgg                             /* (3b) */
     || IsVirtual(pSubSrc->a[0].pTab)     /* (3c) */

     || (p->selFlags & SF_Distinct)!=0    /* (3d) */
    ){
      return 0;
    }
  }
#ifdef SQLITE_EXTRA_IFNULLROW
  else if( iFrom>0 && !isAgg ){
    /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for
    ** every reference to any result column from subquery in a join, even
130422
130423
130424
130425
130426
130427
130428



130429
130430
130431
130432
130433
130434
130435
      testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
      testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
      assert( pSub->pSrc!=0 );
      assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
      if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0    /* (17b) */
       || (pSub1->pPrior && pSub1->op!=TK_ALL)                 /* (17a) */
       || pSub1->pSrc->nSrc<1                                  /* (17c) */



      ){
        return 0;
      }
      testcase( pSub1->pSrc->nSrc>1 );
    }

    /* Restriction (18). */







>
>
>







131801
131802
131803
131804
131805
131806
131807
131808
131809
131810
131811
131812
131813
131814
131815
131816
131817
      testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
      testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
      assert( pSub->pSrc!=0 );
      assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
      if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0    /* (17b) */
       || (pSub1->pPrior && pSub1->op!=TK_ALL)                 /* (17a) */
       || pSub1->pSrc->nSrc<1                                  /* (17c) */
#ifndef SQLITE_OMIT_WINDOWFUNC
       || pSub1->pWin                                          /* (17e) */
#endif
      ){
        return 0;
      }
      testcase( pSub1->pSrc->nSrc>1 );
    }

    /* Restriction (18). */
130676
130677
130678
130679
130680
130681
130682






130683
130684
130685
130686
130687
130688
130689
    ** One is tempted to try to add a and b to combine the limits.  But this
    ** does not work if either limit is negative.
    */
    if( pSub->pLimit ){
      pParent->pLimit = pSub->pLimit;
      pSub->pLimit = 0;
    }






  }

  /* Finially, delete what is left of the subquery and return
  ** success.
  */
  sqlite3SelectDelete(db, pSub1);








>
>
>
>
>
>







132058
132059
132060
132061
132062
132063
132064
132065
132066
132067
132068
132069
132070
132071
132072
132073
132074
132075
132076
132077
    ** One is tempted to try to add a and b to combine the limits.  But this
    ** does not work if either limit is negative.
    */
    if( pSub->pLimit ){
      pParent->pLimit = pSub->pLimit;
      pSub->pLimit = 0;
    }

    /* Recompute the SrcList_item.colUsed masks for the flattened
    ** tables. */
    for(i=0; i<nSubSrc; i++){
      recomputeColumnsUsed(pParent, &pSrc->a[i+iFrom]);
    }
  }

  /* Finially, delete what is left of the subquery and return
  ** success.
  */
  sqlite3SelectDelete(db, pSub1);

130708
130709
130710
130711
130712
130713
130714
130715




130716
130717
130718
130719
130720

130721
130722
130723







130724
130725
130726
130727
130728
130729
130730
130731
130732
130733
130734
130735
130736
130737
130738
130739
130740
130741
130742
130743
130744
130745
130746
130747
130748
130749
130750
  int nConst;      /* Number for COLUMN=CONSTANT terms */
  int nChng;       /* Number of times a constant is propagated */
  Expr **apExpr;   /* [i*2] is COLUMN and [i*2+1] is VALUE */
};

/*
** Add a new entry to the pConst object.  Except, do not add duplicate
** pColumn entires.




*/
static void constInsert(
  WhereConst *pConst,      /* The WhereConst into which we are inserting */
  Expr *pColumn,           /* The COLUMN part of the constraint */
  Expr *pValue             /* The VALUE part of the constraint */

){
  int i;
  assert( pColumn->op==TK_COLUMN );








  /* 2018-10-25 ticket [cf5ed20f]
  ** Make sure the same pColumn is not inserted more than once */
  for(i=0; i<pConst->nConst; i++){
    const Expr *pExpr = pConst->apExpr[i*2];
    assert( pExpr->op==TK_COLUMN );
    if( pExpr->iTable==pColumn->iTable
     && pExpr->iColumn==pColumn->iColumn
    ){
      return;  /* Already present.  Return without doing anything. */
    }
  }

  pConst->nConst++;
  pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
                         pConst->nConst*2*sizeof(Expr*));
  if( pConst->apExpr==0 ){
    pConst->nConst = 0;
  }else{
    if( ExprHasProperty(pValue, EP_FixedCol) ) pValue = pValue->pLeft;
    pConst->apExpr[pConst->nConst*2-2] = pColumn;
    pConst->apExpr[pConst->nConst*2-1] = pValue;
  }
}

/*
** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE







|
>
>
>
>


|
|
|
>



>
>
>
>
>
>
>




|
|
|
|











<







132096
132097
132098
132099
132100
132101
132102
132103
132104
132105
132106
132107
132108
132109
132110
132111
132112
132113
132114
132115
132116
132117
132118
132119
132120
132121
132122
132123
132124
132125
132126
132127
132128
132129
132130
132131
132132
132133
132134
132135
132136
132137
132138
132139
132140
132141
132142

132143
132144
132145
132146
132147
132148
132149
  int nConst;      /* Number for COLUMN=CONSTANT terms */
  int nChng;       /* Number of times a constant is propagated */
  Expr **apExpr;   /* [i*2] is COLUMN and [i*2+1] is VALUE */
};

/*
** Add a new entry to the pConst object.  Except, do not add duplicate
** pColumn entires.  Also, do not add if doing so would not be appropriate.
**
** The caller guarantees the pColumn is a column and pValue is a constant.
** This routine has to do some additional checks before completing the
** insert.
*/
static void constInsert(
  WhereConst *pConst,  /* The WhereConst into which we are inserting */
  Expr *pColumn,       /* The COLUMN part of the constraint */
  Expr *pValue,        /* The VALUE part of the constraint */
  Expr *pExpr          /* Overall expression: COLUMN=VALUE or VALUE=COLUMN */
){
  int i;
  assert( pColumn->op==TK_COLUMN );
  assert( sqlite3ExprIsConstant(pValue) );

  if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
  if( sqlite3ExprAffinity(pValue)!=0 ) return;
  if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){
    return;
  }

  /* 2018-10-25 ticket [cf5ed20f]
  ** Make sure the same pColumn is not inserted more than once */
  for(i=0; i<pConst->nConst; i++){
    const Expr *pE2 = pConst->apExpr[i*2];
    assert( pE2->op==TK_COLUMN );
    if( pE2->iTable==pColumn->iTable
     && pE2->iColumn==pColumn->iColumn
    ){
      return;  /* Already present.  Return without doing anything. */
    }
  }

  pConst->nConst++;
  pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
                         pConst->nConst*2*sizeof(Expr*));
  if( pConst->apExpr==0 ){
    pConst->nConst = 0;
  }else{

    pConst->apExpr[pConst->nConst*2-2] = pColumn;
    pConst->apExpr[pConst->nConst*2-1] = pValue;
  }
}

/*
** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE
130762
130763
130764
130765
130766
130767
130768
130769
130770
130771
130772
130773
130774
130775

130776
130777
130778
130779
130780
130781
130782
130783
130784
130785
130786
130787
130788
130789
130790
130791
130792
130793
130794
130795




130796
130797
130798
130799
130800
130801
130802
    return;
  }
  if( pExpr->op!=TK_EQ ) return;
  pRight = pExpr->pRight;
  pLeft = pExpr->pLeft;
  assert( pRight!=0 );
  assert( pLeft!=0 );
  if( pRight->op==TK_COLUMN
   && !ExprHasProperty(pRight, EP_FixedCol)
   && sqlite3ExprIsConstant(pLeft)
   && sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr))
  ){
    constInsert(pConst, pRight, pLeft);
  }else

  if( pLeft->op==TK_COLUMN
   && !ExprHasProperty(pLeft, EP_FixedCol)
   && sqlite3ExprIsConstant(pRight)
   && sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr))
  ){
    constInsert(pConst, pLeft, pRight);
  }
}

/*
** This is a Walker expression callback.  pExpr is a candidate expression
** to be replaced by a value.  If pExpr is equivalent to one of the
** columns named in pWalker->u.pConst, then overwrite it with its
** corresponding value.
*/
static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
  int i;
  WhereConst *pConst;
  if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
  if( ExprHasProperty(pExpr, EP_FixedCol) ) return WRC_Continue;




  pConst = pWalker->u.pConst;
  for(i=0; i<pConst->nConst; i++){
    Expr *pColumn = pConst->apExpr[i*2];
    if( pColumn==pExpr ) continue;
    if( pColumn->iTable!=pExpr->iTable ) continue;
    if( pColumn->iColumn!=pExpr->iColumn ) continue;
    /* A match is found.  Add the EP_FixedCol property */







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













|
>
>
>
>







132161
132162
132163
132164
132165
132166
132167
132168




132169

132170
132171




132172
132173
132174
132175
132176
132177
132178
132179
132180
132181
132182
132183
132184
132185
132186
132187
132188
132189
132190
132191
132192
132193
132194
132195
132196
132197
    return;
  }
  if( pExpr->op!=TK_EQ ) return;
  pRight = pExpr->pRight;
  pLeft = pExpr->pLeft;
  assert( pRight!=0 );
  assert( pLeft!=0 );
  if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){




    constInsert(pConst,pRight,pLeft,pExpr);

  }
  if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){




    constInsert(pConst,pLeft,pRight,pExpr);
  }
}

/*
** This is a Walker expression callback.  pExpr is a candidate expression
** to be replaced by a value.  If pExpr is equivalent to one of the
** columns named in pWalker->u.pConst, then overwrite it with its
** corresponding value.
*/
static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
  int i;
  WhereConst *pConst;
  if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
  if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
    testcase( ExprHasProperty(pExpr, EP_FixedCol) );
    testcase( ExprHasProperty(pExpr, EP_FromJoin) );
    return WRC_Continue;
  }
  pConst = pWalker->u.pConst;
  for(i=0; i<pConst->nConst; i++){
    Expr *pColumn = pConst->apExpr[i*2];
    if( pColumn==pExpr ) continue;
    if( pColumn->iTable!=pExpr->iTable ) continue;
    if( pColumn->iColumn!=pExpr->iColumn ) continue;
    /* A match is found.  Add the EP_FixedCol property */
130810
130811
130812
130813
130814
130815
130816
130817
130818
130819
130820
130821
130822
130823
130824
130825
130826
130827
  return WRC_Prune;
}

/*
** The WHERE-clause constant propagation optimization.
**
** If the WHERE clause contains terms of the form COLUMN=CONSTANT or
** CONSTANT=COLUMN that must be tree (in other words, if the terms top-level
** AND-connected terms that are not part of a ON clause from a LEFT JOIN)
** then throughout the query replace all other occurrences of COLUMN
** with CONSTANT within the WHERE clause.
**
** For example, the query:
**
**      SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b
**
** Is transformed into
**







|
|
|
<







132205
132206
132207
132208
132209
132210
132211
132212
132213
132214

132215
132216
132217
132218
132219
132220
132221
  return WRC_Prune;
}

/*
** The WHERE-clause constant propagation optimization.
**
** If the WHERE clause contains terms of the form COLUMN=CONSTANT or
** CONSTANT=COLUMN that are top-level AND-connected terms that are not
** part of a ON clause from a LEFT JOIN, then throughout the query
** replace all other occurrences of COLUMN with CONSTANT.

**
** For example, the query:
**
**      SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b
**
** Is transformed into
**
131017
131018
131019
131020
131021
131022
131023
131024
131025
131026
131027
131028
131029
131030
131031
131032
131033
131034

131035

131036
131037
131038
131039
131040
131041
131042
** analysis.
*/
static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
  int eRet = WHERE_ORDERBY_NORMAL;      /* Return value */
  ExprList *pEList = pFunc->x.pList;    /* Arguments to agg function */
  const char *zFunc;                    /* Name of aggregate function pFunc */
  ExprList *pOrderBy;
  u8 sortFlags;

  assert( *ppMinMax==0 );
  assert( pFunc->op==TK_AGG_FUNCTION );
  assert( !IsWindowFunc(pFunc) );
  if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) ){
    return eRet;
  }
  zFunc = pFunc->u.zToken;
  if( sqlite3StrICmp(zFunc, "min")==0 ){
    eRet = WHERE_ORDERBY_MIN;

    sortFlags = KEYINFO_ORDER_BIGNULL;

  }else if( sqlite3StrICmp(zFunc, "max")==0 ){
    eRet = WHERE_ORDERBY_MAX;
    sortFlags = KEYINFO_ORDER_DESC;
  }else{
    return eRet;
  }
  *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);







|










>
|
>







132411
132412
132413
132414
132415
132416
132417
132418
132419
132420
132421
132422
132423
132424
132425
132426
132427
132428
132429
132430
132431
132432
132433
132434
132435
132436
132437
132438
** analysis.
*/
static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
  int eRet = WHERE_ORDERBY_NORMAL;      /* Return value */
  ExprList *pEList = pFunc->x.pList;    /* Arguments to agg function */
  const char *zFunc;                    /* Name of aggregate function pFunc */
  ExprList *pOrderBy;
  u8 sortFlags = 0;

  assert( *ppMinMax==0 );
  assert( pFunc->op==TK_AGG_FUNCTION );
  assert( !IsWindowFunc(pFunc) );
  if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) ){
    return eRet;
  }
  zFunc = pFunc->u.zToken;
  if( sqlite3StrICmp(zFunc, "min")==0 ){
    eRet = WHERE_ORDERBY_MIN;
    if( sqlite3ExprCanBeNull(pEList->a[0].pExpr) ){
      sortFlags = KEYINFO_ORDER_BIGNULL;
    }
  }else if( sqlite3StrICmp(zFunc, "max")==0 ){
    eRet = WHERE_ORDERBY_MAX;
    sortFlags = KEYINFO_ORDER_DESC;
  }else{
    return eRet;
  }
  *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
131162
131163
131164
131165
131166
131167
131168



131169
131170
131171
131172
131173
131174
131175
  p->pWhere = 0;
  pNew->pGroupBy = 0;
  pNew->pHaving = 0;
  pNew->pOrderBy = 0;
  p->pPrior = 0;
  p->pNext = 0;
  p->pWith = 0;



  p->selFlags &= ~SF_Compound;
  assert( (p->selFlags & SF_Converted)==0 );
  p->selFlags |= SF_Converted;
  assert( pNew->pPrior!=0 );
  pNew->pPrior->pNext = pNew;
  pNew->pLimit = 0;
  return WRC_Continue;







>
>
>







132558
132559
132560
132561
132562
132563
132564
132565
132566
132567
132568
132569
132570
132571
132572
132573
132574
  p->pWhere = 0;
  pNew->pGroupBy = 0;
  pNew->pHaving = 0;
  pNew->pOrderBy = 0;
  p->pPrior = 0;
  p->pNext = 0;
  p->pWith = 0;
#ifndef SQLITE_OMIT_WINDOWFUNC
  p->pWinDefn = 0;
#endif
  p->selFlags &= ~SF_Compound;
  assert( (p->selFlags & SF_Converted)==0 );
  p->selFlags |= SF_Converted;
  assert( pNew->pPrior!=0 );
  pNew->pPrior->pNext = pNew;
  pNew->pLimit = 0;
  return WRC_Continue;
131384
131385
131386
131387
131388
131389
131390
131391
131392
131393
131394
131395
131396
131397
131398
** names and other FROM clause elements. 
*/
static void selectPopWith(Walker *pWalker, Select *p){
  Parse *pParse = pWalker->pParse;
  if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){
    With *pWith = findRightmost(p)->pWith;
    if( pWith!=0 ){
      assert( pParse->pWith==pWith );
      pParse->pWith = pWith->pOuter;
    }
  }
}
#else
#define selectPopWith 0
#endif







|







132783
132784
132785
132786
132787
132788
132789
132790
132791
132792
132793
132794
132795
132796
132797
** names and other FROM clause elements. 
*/
static void selectPopWith(Walker *pWalker, Select *p){
  Parse *pParse = pWalker->pParse;
  if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){
    With *pWith = findRightmost(p)->pWith;
    if( pWith!=0 ){
      assert( pParse->pWith==pWith || pParse->nErr );
      pParse->pWith = pWith->pOuter;
    }
  }
}
#else
#define selectPopWith 0
#endif
131515
131516
131517
131518
131519
131520
131521
131522
131523
131524
131525
131526
131527
131528
131529
131530
131531










131532
131533
131534
131535
131536
131537
131538
131539
131540
131541
131542
131543
131544
131545
131546
131547
131548
131549
131550
131551
131552
131553
131554
131555
131556
131557
131558
        pFrom->pTab = 0;
        return WRC_Abort;
      }
      pTab->nTabRef++;
      if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
        return WRC_Abort;
      }
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
      if( IsVirtual(pTab) || pTab->pSelect ){
        i16 nCol;
        u8 eCodeOrig = pWalker->eCode;
        if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
        assert( pFrom->pSelect==0 );
        if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
          sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
              pTab->zName);
        }










        pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
        nCol = pTab->nCol;
        pTab->nCol = -1;
        pWalker->eCode = 1;  /* Turn on Select.selId renumbering */
        sqlite3WalkSelect(pWalker, pFrom->pSelect);
        pWalker->eCode = eCodeOrig;
        pTab->nCol = nCol;
      }
#endif
    }

    /* Locate the index named by the INDEXED BY clause, if any. */
    if( sqlite3IndexedByLookup(pParse, pFrom) ){
      return WRC_Abort;
    }
  }

  /* Process NATURAL keywords, and ON and USING clauses of joins.
  */
  if( db->mallocFailed || sqliteProcessJoin(pParse, p) ){
    return WRC_Abort;
  }

  /* For every "*" that occurs in the column list, insert the names of
  ** all columns in all tables.  And for every TABLE.* insert the names
  ** of all columns in TABLE.  The parser inserted a special expression
  ** with the TK_ASTERISK operator for each "*" that it found in the column







|







|

>
>
>
>
>
>
>
>
>
>



















|







132914
132915
132916
132917
132918
132919
132920
132921
132922
132923
132924
132925
132926
132927
132928
132929
132930
132931
132932
132933
132934
132935
132936
132937
132938
132939
132940
132941
132942
132943
132944
132945
132946
132947
132948
132949
132950
132951
132952
132953
132954
132955
132956
132957
132958
132959
132960
132961
132962
132963
132964
132965
132966
132967
        pFrom->pTab = 0;
        return WRC_Abort;
      }
      pTab->nTabRef++;
      if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
        return WRC_Abort;
      }
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
      if( IsVirtual(pTab) || pTab->pSelect ){
        i16 nCol;
        u8 eCodeOrig = pWalker->eCode;
        if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
        assert( pFrom->pSelect==0 );
        if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
          sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
            pTab->zName);
        }
#ifndef SQLITE_OMIT_VIRTUALTABLE
        if( IsVirtual(pTab)
         && pFrom->fg.fromDDL
         && ALWAYS(pTab->pVTable!=0)
         && pTab->pVTable->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
        ){
          sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
                                  pTab->zName);
        }
#endif
        pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
        nCol = pTab->nCol;
        pTab->nCol = -1;
        pWalker->eCode = 1;  /* Turn on Select.selId renumbering */
        sqlite3WalkSelect(pWalker, pFrom->pSelect);
        pWalker->eCode = eCodeOrig;
        pTab->nCol = nCol;
      }
#endif
    }

    /* Locate the index named by the INDEXED BY clause, if any. */
    if( sqlite3IndexedByLookup(pParse, pFrom) ){
      return WRC_Abort;
    }
  }

  /* Process NATURAL keywords, and ON and USING clauses of joins.
  */
  if( pParse->nErr || db->mallocFailed || sqliteProcessJoin(pParse, p) ){
    return WRC_Abort;
  }

  /* For every "*" that occurs in the column list, insert the names of
  ** all columns in all tables.  And for every TABLE.* insert the names
  ** of all columns in TABLE.  The parser inserted a special expression
  ** with the TK_ASTERISK operator for each "*" that it found in the column
131591
131592
131593
131594
131595
131596
131597
131598
131599
131600
131601
131602
131603
131604
131605
131606
131607
131608
      if( pE->op!=TK_ASTERISK
       && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK)
      ){
        /* This particular expression does not need to be expanded.
        */
        pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
        if( pNew ){
          pNew->a[pNew->nExpr-1].zName = a[k].zName;
          pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan;
          a[k].zName = 0;
          a[k].zSpan = 0;
        }
        a[k].pExpr = 0;
      }else{
        /* This expression is a "*" or a "TABLE.*" and needs to be
        ** expanded. */
        int tableSeen = 0;      /* Set to 1 when TABLE matches */
        char *zTName = 0;       /* text of name of TABLE */







|
|
|
<







133000
133001
133002
133003
133004
133005
133006
133007
133008
133009

133010
133011
133012
133013
133014
133015
133016
      if( pE->op!=TK_ASTERISK
       && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK)
      ){
        /* This particular expression does not need to be expanded.
        */
        pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
        if( pNew ){
          pNew->a[pNew->nExpr-1].zEName = a[k].zEName;
          pNew->a[pNew->nExpr-1].eEName = a[k].eEName;
          a[k].zEName = 0;

        }
        a[k].pExpr = 0;
      }else{
        /* This expression is a "*" or a "TABLE.*" and needs to be
        ** expanded. */
        int tableSeen = 0;      /* Set to 1 when TABLE matches */
        char *zTName = 0;       /* text of name of TABLE */
131633
131634
131635
131636
131637
131638
131639
131640
131641
131642
131643
131644
131645
131646
131647
131648
131649
131650
131651
131652
131653
131654
131655
131656
131657
131658
131659
131660
131661
131662
131663
131664
131665
            char *zName = pTab->aCol[j].zName;
            char *zColname;  /* The computed column name */
            char *zToFree;   /* Malloced string that needs to be freed */
            Token sColname;  /* Computed column name as a token */

            assert( zName );
            if( zTName && pSub
             && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
            ){
              continue;
            }

            /* If a column is marked as 'hidden', omit it from the expanded
            ** result-set list unless the SELECT has the SF_IncludeHidden
            ** bit set.
            */
            if( (p->selFlags & SF_IncludeHidden)==0
             && IsHiddenColumn(&pTab->aCol[j]) 
            ){
              continue;
            }
            tableSeen = 1;

            if( i>0 && zTName==0 ){
              if( (pFrom->fg.jointype & JT_NATURAL)!=0
                && tableAndColumnIndex(pTabList, i, zName, 0, 0)
              ){
                /* In a NATURAL join, omit the join columns from the 
                ** table to the right of the join */
                continue;
              }
              if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){
                /* In a join with a USING clause, omit columns in the







|

















|







133041
133042
133043
133044
133045
133046
133047
133048
133049
133050
133051
133052
133053
133054
133055
133056
133057
133058
133059
133060
133061
133062
133063
133064
133065
133066
133067
133068
133069
133070
133071
133072
133073
            char *zName = pTab->aCol[j].zName;
            char *zColname;  /* The computed column name */
            char *zToFree;   /* Malloced string that needs to be freed */
            Token sColname;  /* Computed column name as a token */

            assert( zName );
            if( zTName && pSub
             && sqlite3MatchEName(&pSub->pEList->a[j], 0, zTName, 0)==0
            ){
              continue;
            }

            /* If a column is marked as 'hidden', omit it from the expanded
            ** result-set list unless the SELECT has the SF_IncludeHidden
            ** bit set.
            */
            if( (p->selFlags & SF_IncludeHidden)==0
             && IsHiddenColumn(&pTab->aCol[j]) 
            ){
              continue;
            }
            tableSeen = 1;

            if( i>0 && zTName==0 ){
              if( (pFrom->fg.jointype & JT_NATURAL)!=0
                && tableAndColumnIndex(pTabList, i, zName, 0, 0, 1)
              ){
                /* In a NATURAL join, omit the join columns from the 
                ** table to the right of the join */
                continue;
              }
              if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){
                /* In a join with a USING clause, omit columns in the
131684
131685
131686
131687
131688
131689
131690
131691
131692

131693
131694
131695
131696
131697
131698
131699
131700
131701
131702
131703
131704
131705
131706
131707
131708
              }
            }else{
              pExpr = pRight;
            }
            pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
            sqlite3TokenInit(&sColname, zColname);
            sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
            if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
              struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];

              if( pSub ){
                pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
                testcase( pX->zSpan==0 );
              }else{
                pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
                                           zSchemaName, zTabName, zColname);
                testcase( pX->zSpan==0 );
              }
              pX->bSpanIsTab = 1;
            }
            sqlite3DbFree(db, zToFree);
          }
        }
        if( !tableSeen ){
          if( zTName ){
            sqlite3ErrorMsg(pParse, "no such table: %s", zTName);







|

>

|
|

|

|

|







133092
133093
133094
133095
133096
133097
133098
133099
133100
133101
133102
133103
133104
133105
133106
133107
133108
133109
133110
133111
133112
133113
133114
133115
133116
133117
              }
            }else{
              pExpr = pRight;
            }
            pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
            sqlite3TokenInit(&sColname, zColname);
            sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
            if( pNew && (p->selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){
              struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
              sqlite3DbFree(db, pX->zEName);
              if( pSub ){
                pX->zEName = sqlite3DbStrDup(db, pSub->pEList->a[j].zEName);
                testcase( pX->zEName==0 );
              }else{
                pX->zEName = sqlite3MPrintf(db, "%s.%s.%s",
                                           zSchemaName, zTabName, zColname);
                testcase( pX->zEName==0 );
              }
              pX->eEName = ENAME_TAB;
            }
            sqlite3DbFree(db, zToFree);
          }
        }
        if( !tableSeen ){
          if( zTName ){
            sqlite3ErrorMsg(pParse, "no such table: %s", zTName);
131887
131888
131889
131890
131891
131892
131893

131894
131895
131896
131897
131898
131899
131900
*/
static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
  Vdbe *v = pParse->pVdbe;
  int i;
  struct AggInfo_func *pFunc;
  int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
  if( nReg==0 ) return;

#ifdef SQLITE_DEBUG
  /* Verify that all AggInfo registers are within the range specified by
  ** AggInfo.mnReg..AggInfo.mxReg */
  assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
  for(i=0; i<pAggInfo->nColumn; i++){
    assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
         && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );







>







133296
133297
133298
133299
133300
133301
133302
133303
133304
133305
133306
133307
133308
133309
133310
*/
static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
  Vdbe *v = pParse->pVdbe;
  int i;
  struct AggInfo_func *pFunc;
  int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
  if( nReg==0 ) return;
  if( pParse->nErr ) return;
#ifdef SQLITE_DEBUG
  /* Verify that all AggInfo registers are within the range specified by
  ** AggInfo.mnReg..AggInfo.mxReg */
  assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
  for(i=0; i<pAggInfo->nColumn; i++){
    assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
         && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
132028
132029
132030
132031
132032
132033
132034
132035
132036
132037
132038
132039
132040
132041
132042
  }
  for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
    sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
  }

  pAggInfo->directMode = 0;
  if( addrHitTest ){
    sqlite3VdbeJumpHere(v, addrHitTest);
  }
}

/*
** Add a single OP_Explain instruction to the VDBE to explain a simple
** count(*) query ("SELECT count(*) FROM pTab").
*/







|







133438
133439
133440
133441
133442
133443
133444
133445
133446
133447
133448
133449
133450
133451
133452
  }
  for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
    sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
  }

  pAggInfo->directMode = 0;
  if( addrHitTest ){
    sqlite3VdbeJumpHereOrPopInst(v, addrHitTest);
  }
}

/*
** Add a single OP_Explain instruction to the VDBE to explain a simple
** count(*) query ("SELECT count(*) FROM pTab").
*/
132321
132322
132323
132324
132325
132326
132327
132328


132329
132330
132331
132332
132333
132334
132335
#endif

  if( pDest->eDest==SRT_Output ){
    generateColumnNames(pParse, p);
  }

#ifndef SQLITE_OMIT_WINDOWFUNC
  if( sqlite3WindowRewrite(pParse, p) ){


    goto select_end;
  }
#if SELECTTRACE_ENABLED
  if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
    SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
    sqlite3TreeViewSelect(0, p, 0);
  }







|
>
>







133731
133732
133733
133734
133735
133736
133737
133738
133739
133740
133741
133742
133743
133744
133745
133746
133747
#endif

  if( pDest->eDest==SRT_Output ){
    generateColumnNames(pParse, p);
  }

#ifndef SQLITE_OMIT_WINDOWFUNC
  rc = sqlite3WindowRewrite(pParse, p);
  if( rc ){
    assert( db->mallocFailed || pParse->nErr>0 );
    goto select_end;
  }
#if SELECTTRACE_ENABLED
  if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
    SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
    sqlite3TreeViewSelect(0, p, 0);
  }
132657
132658
132659
132660
132661
132662
132663



132664
132665
132666

132667
132668
132669
132670
132671
132672
132673
  ** The second form is preferred as a single index (or temp-table) may be 
  ** used for both the ORDER BY and DISTINCT processing. As originally 
  ** written the query must use a temp-table for at least one of the ORDER 
  ** BY and DISTINCT, and an index or separate temp-table for the other.
  */
  if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct 
   && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0



  ){
    p->selFlags &= ~SF_Distinct;
    pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);

    /* Notice that even thought SF_Distinct has been cleared from p->selFlags,
    ** the sDistinct.isTnct is still set.  Hence, isTnct represents the
    ** original setting of the SF_Distinct flag, not the current setting */
    assert( sDistinct.isTnct );

#if SELECTTRACE_ENABLED
    if( sqlite3SelectTrace & 0x400 ){







>
>
>



>







134069
134070
134071
134072
134073
134074
134075
134076
134077
134078
134079
134080
134081
134082
134083
134084
134085
134086
134087
134088
134089
  ** The second form is preferred as a single index (or temp-table) may be 
  ** used for both the ORDER BY and DISTINCT processing. As originally 
  ** written the query must use a temp-table for at least one of the ORDER 
  ** BY and DISTINCT, and an index or separate temp-table for the other.
  */
  if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct 
   && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
#ifndef SQLITE_OMIT_WINDOWFUNC
   && p->pWin==0
#endif
  ){
    p->selFlags &= ~SF_Distinct;
    pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
    p->selFlags |= SF_Aggregate;
    /* Notice that even thought SF_Distinct has been cleared from p->selFlags,
    ** the sDistinct.isTnct is still set.  Hence, isTnct represents the
    ** original setting of the SF_Distinct flag, not the current setting */
    assert( sDistinct.isTnct );

#if SELECTTRACE_ENABLED
    if( sqlite3SelectTrace & 0x400 ){
132734
132735
132736
132737
132738
132739
132740
132741
132742
132743
132744
132745
132746
132747
132748
  if( !isAgg && pGroupBy==0 ){
    /* No aggregate functions and no GROUP BY clause */
    u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
                   | (p->selFlags & SF_FixedLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
    Window *pWin = p->pWin;      /* Master window object (or NULL) */
    if( pWin ){
      sqlite3WindowCodeInit(pParse, pWin);
    }
#endif
    assert( WHERE_USE_LIMIT==SF_FixedLimit );


    /* Begin the database scan. */
    SELECTTRACE(1,pParse,p,("WhereBegin\n"));







|







134150
134151
134152
134153
134154
134155
134156
134157
134158
134159
134160
134161
134162
134163
134164
  if( !isAgg && pGroupBy==0 ){
    /* No aggregate functions and no GROUP BY clause */
    u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
                   | (p->selFlags & SF_FixedLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
    Window *pWin = p->pWin;      /* Master window object (or NULL) */
    if( pWin ){
      sqlite3WindowCodeInit(pParse, p);
    }
#endif
    assert( WHERE_USE_LIMIT==SF_FixedLimit );


    /* Begin the database scan. */
    SELECTTRACE(1,pParse,p,("WhereBegin\n"));
134098
134099
134100
134101
134102
134103
134104
134105
134106
134107
134108
134109
134110
134111
134112

  assert( pName->nSrc==1 );
  zDb = pName->a[0].zDatabase;
  zName = pName->a[0].zName;
  assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
  for(i=OMIT_TEMPDB; i<db->nDb; i++){
    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue;
    assert( sqlite3SchemaMutexHeld(db, j, 0) );
    pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
    if( pTrigger ) break;
  }
  if( !pTrigger ){
    if( !noErr ){
      sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);







|







135514
135515
135516
135517
135518
135519
135520
135521
135522
135523
135524
135525
135526
135527
135528

  assert( pName->nSrc==1 );
  zDb = pName->a[0].zDatabase;
  zName = pName->a[0].zName;
  assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
  for(i=OMIT_TEMPDB; i<db->nDb; i++){
    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
    assert( sqlite3SchemaMutexHeld(db, j, 0) );
    pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
    if( pTrigger ) break;
  }
  if( !pTrigger ){
    if( !noErr ){
      sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
134180
134181
134182
134183
134184
134185
134186
134187

134188



134189
134190
134191
134192
134193
134194
134195
134196
134197
134198
134199
134200
134201
134202
134203
134204
134205
134206
134207
134208
134209
134210
134211
134212
134213
134214
134215
134216
  pHash = &(db->aDb[iDb].pSchema->trigHash);
  pTrigger = sqlite3HashInsert(pHash, zName, 0);
  if( ALWAYS(pTrigger) ){
    if( pTrigger->pSchema==pTrigger->pTabSchema ){
      Table *pTab = tableOfTrigger(pTrigger);
      if( pTab ){
        Trigger **pp;
        for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));

        *pp = (*pp)->pNext;



      }
    }
    sqlite3DeleteTrigger(db, pTrigger);
    db->mDbFlags |= DBFLAG_SchemaChange;
  }
}

/*
** pEList is the SET clause of an UPDATE statement.  Each entry
** in pEList is of the format <id>=<expr>.  If any of the entries
** in pEList have an <id> which matches an identifier in pIdList,
** then return TRUE.  If pIdList==NULL, then it is considered a
** wildcard that matches anything.  Likewise if pEList==NULL then
** it matches anything so always return true.  Return false only
** if there is no match.
*/
static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
  int e;
  if( pIdList==0 || NEVER(pEList==0) ) return 1;
  for(e=0; e<pEList->nExpr; e++){
    if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
  }
  return 0; 
}

/*
** Return a list of all triggers on table pTab if there exists at least
** one trigger that must be fired when an operation of type 'op' is 







|
>
|
>
>
>




















|







135596
135597
135598
135599
135600
135601
135602
135603
135604
135605
135606
135607
135608
135609
135610
135611
135612
135613
135614
135615
135616
135617
135618
135619
135620
135621
135622
135623
135624
135625
135626
135627
135628
135629
135630
135631
135632
135633
135634
135635
135636
  pHash = &(db->aDb[iDb].pSchema->trigHash);
  pTrigger = sqlite3HashInsert(pHash, zName, 0);
  if( ALWAYS(pTrigger) ){
    if( pTrigger->pSchema==pTrigger->pTabSchema ){
      Table *pTab = tableOfTrigger(pTrigger);
      if( pTab ){
        Trigger **pp;
        for(pp=&pTab->pTrigger; *pp; pp=&((*pp)->pNext)){
          if( *pp==pTrigger ){
            *pp = (*pp)->pNext;
            break;
          }
        }
      }
    }
    sqlite3DeleteTrigger(db, pTrigger);
    db->mDbFlags |= DBFLAG_SchemaChange;
  }
}

/*
** pEList is the SET clause of an UPDATE statement.  Each entry
** in pEList is of the format <id>=<expr>.  If any of the entries
** in pEList have an <id> which matches an identifier in pIdList,
** then return TRUE.  If pIdList==NULL, then it is considered a
** wildcard that matches anything.  Likewise if pEList==NULL then
** it matches anything so always return true.  Return false only
** if there is no match.
*/
static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
  int e;
  if( pIdList==0 || NEVER(pEList==0) ) return 1;
  for(e=0; e<pEList->nExpr; e++){
    if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1;
  }
  return 0; 
}

/*
** Return a list of all triggers on table pTab if there exists at least
** one trigger that must be fired when an operation of type 'op' is 
134906
134907
134908
134909
134910
134911
134912

134913
134914
134915
134916
134917
134918
134919
  int iEph = 0;          /* Ephemeral table holding all primary key values */
  int nKey = 0;          /* Number of elements in regKey for WITHOUT ROWID */
  int aiCurOnePass[2];   /* The write cursors opened by WHERE_ONEPASS */
  int addrOpen = 0;      /* Address of OP_OpenEphemeral */
  int iPk = 0;           /* First of nPk cells holding PRIMARY KEY value */
  i16 nPk = 0;           /* Number of components of the PRIMARY KEY */
  int bReplace = 0;      /* True if REPLACE conflict resolution might happen */


  /* Register Allocations */
  int regRowCount = 0;   /* A count of rows changed */
  int regOldRowid = 0;   /* The old rowid */
  int regNewRowid = 0;   /* The new rowid */
  int regNew = 0;        /* Content of the NEW.* table in triggers */
  int regOld = 0;        /* Content of OLD.* table in triggers */







>







136326
136327
136328
136329
136330
136331
136332
136333
136334
136335
136336
136337
136338
136339
136340
  int iEph = 0;          /* Ephemeral table holding all primary key values */
  int nKey = 0;          /* Number of elements in regKey for WITHOUT ROWID */
  int aiCurOnePass[2];   /* The write cursors opened by WHERE_ONEPASS */
  int addrOpen = 0;      /* Address of OP_OpenEphemeral */
  int iPk = 0;           /* First of nPk cells holding PRIMARY KEY value */
  i16 nPk = 0;           /* Number of components of the PRIMARY KEY */
  int bReplace = 0;      /* True if REPLACE conflict resolution might happen */
  int bFinishSeek = 1;   /* The OP_FinishSeek opcode is needed */

  /* Register Allocations */
  int regRowCount = 0;   /* A count of rows changed */
  int regOldRowid = 0;   /* The old rowid */
  int regNewRowid = 0;   /* The new rowid */
  int regNew = 0;        /* Content of the NEW.* table in triggers */
  int regOld = 0;        /* Content of OLD.* table in triggers */
135020
135021
135022
135023
135024
135025
135026
135027
135028
135029
135030
135031
135032
135033
135034
  */
  chngRowid = chngPk = 0;
  for(i=0; i<pChanges->nExpr; i++){
    if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
      goto update_cleanup;
    }
    for(j=0; j<pTab->nCol; j++){
      if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
        if( j==pTab->iPKey ){
          chngRowid = 1;
          pRowidExpr = pChanges->a[i].pExpr;
        }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
          chngPk = 1;
        }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS







|







136441
136442
136443
136444
136445
136446
136447
136448
136449
136450
136451
136452
136453
136454
136455
  */
  chngRowid = chngPk = 0;
  for(i=0; i<pChanges->nExpr; i++){
    if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
      goto update_cleanup;
    }
    for(j=0; j<pTab->nCol; j++){
      if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zEName)==0 ){
        if( j==pTab->iPKey ){
          chngRowid = 1;
          pRowidExpr = pChanges->a[i].pExpr;
        }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
          chngPk = 1;
        }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
135042
135043
135044
135045
135046
135047
135048
135049
135050
135051
135052
135053
135054
135055
135056
135057
135058
135059
135060
135061
        }
#endif
        aXRef[j] = i;
        break;
      }
    }
    if( j>=pTab->nCol ){
      if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){
        j = -1;
        chngRowid = 1;
        pRowidExpr = pChanges->a[i].pExpr;
      }else{
        sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
        pParse->checkSchema = 1;
        goto update_cleanup;
      }
    }
#ifndef SQLITE_OMIT_AUTHORIZATION
    {
      int rc;







|




|







136463
136464
136465
136466
136467
136468
136469
136470
136471
136472
136473
136474
136475
136476
136477
136478
136479
136480
136481
136482
        }
#endif
        aXRef[j] = i;
        break;
      }
    }
    if( j>=pTab->nCol ){
      if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){
        j = -1;
        chngRowid = 1;
        pRowidExpr = pChanges->a[i].pExpr;
      }else{
        sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName);
        pParse->checkSchema = 1;
        goto update_cleanup;
      }
    }
#ifndef SQLITE_OMIT_AUTHORIZATION
    {
      int rc;
135239
135240
135241
135242
135243
135244
135245

135246
135247
135248
135249
135250
135251
135252
    ** the outer INSERT and the data cursor should be pointing at the row
    ** that is to be updated.  So bypass the code that searches for the
    ** row(s) to be updated.
    */
    pWInfo = 0;
    eOnePass = ONEPASS_SINGLE;
    sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);

  }else{
    /* Begin the database scan. 
    **
    ** Do not consider a single-pass strategy for a multi-row update if
    ** there are any triggers or foreign keys to process, or rows may
    ** be deleted as a result of REPLACE conflict handling. Any of these
    ** things might disturb a cursor being used to scan through the table







>







136660
136661
136662
136663
136664
136665
136666
136667
136668
136669
136670
136671
136672
136673
136674
    ** the outer INSERT and the data cursor should be pointing at the row
    ** that is to be updated.  So bypass the code that searches for the
    ** row(s) to be updated.
    */
    pWInfo = 0;
    eOnePass = ONEPASS_SINGLE;
    sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
    bFinishSeek = 0;
  }else{
    /* Begin the database scan. 
    **
    ** Do not consider a single-pass strategy for a multi-row update if
    ** there are any triggers or foreign keys to process, or rows may
    ** be deleted as a result of REPLACE conflict handling. Any of these
    ** things might disturb a cursor being used to scan through the table
135265
135266
135267
135268
135269
135270
135271

135272
135273
135274
135275
135276
135277
135278
    **
    **   UPDATE t1 SET b=b+1 WHERE b>?
    **
    ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
    ** strategy that uses an index for which one or more columns are being
    ** updated.  */
    eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);

    if( eOnePass!=ONEPASS_SINGLE ){
      sqlite3MultiWrite(pParse);
      if( eOnePass==ONEPASS_MULTI ){
        int iCur = aiCurOnePass[1];
        if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
          eOnePass = ONEPASS_OFF;
        }







>







136687
136688
136689
136690
136691
136692
136693
136694
136695
136696
136697
136698
136699
136700
136701
    **
    **   UPDATE t1 SET b=b+1 WHERE b>?
    **
    ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
    ** strategy that uses an index for which one or more columns are being
    ** updated.  */
    eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
    bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
    if( eOnePass!=ONEPASS_SINGLE ){
      sqlite3MultiWrite(pParse);
      if( eOnePass==ONEPASS_MULTI ){
        int iCur = aiCurOnePass[1];
        if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
          eOnePass = ONEPASS_OFF;
        }
135328
135329
135330
135331
135332
135333
135334
135335


135336
135337
135338
135339
135340
135341
135342
      }
  
      if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
        addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
      }
      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
                                 aToOpen, 0, 0);
      if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);


    }
  
    /* Top of the update loop */
    if( eOnePass!=ONEPASS_OFF ){
      if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
        assert( pPk );
        sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey);







|
>
>







136751
136752
136753
136754
136755
136756
136757
136758
136759
136760
136761
136762
136763
136764
136765
136766
136767
      }
  
      if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
        addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
      }
      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
                                 aToOpen, 0, 0);
      if( addrOnce ){
        sqlite3VdbeJumpHereOrPopInst(v, addrOnce);
      }
    }
  
    /* Top of the update loop */
    if( eOnePass!=ONEPASS_OFF ){
      if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
        assert( pPk );
        sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey);
135428
135429
135430
135431
135432
135433
135434

135435
135436
135437
135438
135439
135440
135441
        ** into a register. This is done if there are no BEFORE triggers, or
        ** if there are one or more BEFORE triggers that use this value via
        ** a new.* reference in a trigger program.
        */
        testcase( i==31 );
        testcase( i==32 );
        sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);

      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, k);
      }
    }
  }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
  if( pTab->tabFlags & TF_HasGenerated ){







>







136853
136854
136855
136856
136857
136858
136859
136860
136861
136862
136863
136864
136865
136866
136867
        ** into a register. This is done if there are no BEFORE triggers, or
        ** if there are one or more BEFORE triggers that use this value via
        ** a new.* reference in a trigger program.
        */
        testcase( i==31 );
        testcase( i==32 );
        sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
        bFinishSeek = 0;
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, k);
      }
    }
  }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
  if( pTab->tabFlags & TF_HasGenerated ){
135514
135515
135516
135517
135518
135519
135520









135521
135522
135523
135524
135525
135526
135527
    /* Do FK constraint checks. */
    if( hasFK ){
      sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey);
    }

    /* Delete the index entries associated with the current record.  */
    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);










    /* If changing the rowid value, or if there are foreign key constraints
    ** to process, delete the old record. Otherwise, add a noop OP_Delete
    ** to invoke the pre-update hook.
    **
    ** That (regNew==regnewRowid+1) is true is also important for the 
    ** pre-update hook. If the caller invokes preupdate_new(), the returned







>
>
>
>
>
>
>
>
>







136940
136941
136942
136943
136944
136945
136946
136947
136948
136949
136950
136951
136952
136953
136954
136955
136956
136957
136958
136959
136960
136961
136962
    /* Do FK constraint checks. */
    if( hasFK ){
      sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey);
    }

    /* Delete the index entries associated with the current record.  */
    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);

    /* We must run the OP_FinishSeek opcode to resolve a prior
    ** OP_DeferredSeek if there is any possibility that there have been
    ** no OP_Column opcodes since the OP_DeferredSeek was issued.  But
    ** we want to avoid the OP_FinishSeek if possible, as running it
    ** costs CPU cycles. */
    if( bFinishSeek ){
      sqlite3VdbeAddOp1(v, OP_FinishSeek, iDataCur);
    }

    /* If changing the rowid value, or if there are foreign key constraints
    ** to process, delete the old record. Otherwise, add a noop OP_Delete
    ** to invoke the pre-update hook.
    **
    ** That (regNew==regnewRowid+1) is true is also important for the 
    ** pre-update hook. If the caller invokes preupdate_new(), the returned
136012
136013
136014
136015
136016
136017
136018

136019
136020
136021
136022
136023
136024
136025
                    pTab->aCol[pPk->aiColumn[i]].zName));
      }
      sqlite3VdbeVerifyAbortable(v, OE_Abort);
      i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
      VdbeCoverage(v);
      sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0, 
            "corrupt database", P4_STATIC);

      sqlite3VdbeJumpHere(v, i);
    }
  }
  /* pUpsert does not own pUpsertSrc - the outer INSERT statement does.  So
  ** we have to make a copy before passing it down into sqlite3Update() */
  pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
  /* excluded.* columns of type REAL need to be converted to a hard real */







>







137447
137448
137449
137450
137451
137452
137453
137454
137455
137456
137457
137458
137459
137460
137461
                    pTab->aCol[pPk->aiColumn[i]].zName));
      }
      sqlite3VdbeVerifyAbortable(v, OE_Abort);
      i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
      VdbeCoverage(v);
      sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0, 
            "corrupt database", P4_STATIC);
      sqlite3MayAbort(pParse);
      sqlite3VdbeJumpHere(v, i);
    }
  }
  /* pUpsert does not own pUpsertSrc - the outer INSERT statement does.  So
  ** we have to make a copy before passing it down into sqlite3Update() */
  pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
  /* excluded.* columns of type REAL need to be converted to a hard real */
136270
136271
136272
136273
136274
136275
136276
136277
136278
136279
136280
136281
136282
136283
136284
136285
136286
136287
136288
136289
136290
136291
136292
136293
136294
136295
    if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
      rc = SQLITE_ERROR;
      sqlite3SetString(pzErrMsg, db, "output file already exists");
      goto end_of_vacuum;
    }
    db->mDbFlags |= DBFLAG_VacuumInto;
  }
  nRes = sqlite3BtreeGetOptimalReserve(pMain);

  /* A VACUUM cannot change the pagesize of an encrypted database. */
#ifdef SQLITE_HAS_CODEC
  if( db->nextPagesize ){
    extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
    int nKey;
    char *zKey;
    sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey);
    if( nKey ) db->nextPagesize = 0;
  }
#endif

  sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
  sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
  sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);

  /* Begin a transaction and take an exclusive lock on the main database
  ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,







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







137706
137707
137708
137709
137710
137711
137712
137713











137714
137715
137716
137717
137718
137719
137720
    if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
      rc = SQLITE_ERROR;
      sqlite3SetString(pzErrMsg, db, "output file already exists");
      goto end_of_vacuum;
    }
    db->mDbFlags |= DBFLAG_VacuumInto;
  }
  nRes = sqlite3BtreeGetRequestedReserve(pMain);












  sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
  sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
  sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);

  /* Begin a transaction and take an exclusive lock on the main database
  ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
136911
136912
136913
136914
136915
136916
136917


136918
136919
136920
136921
136922
136923
136924
  */
  if( !db->init.busy ){
    char *zStmt;
    char *zWhere;
    int iDb;
    int iReg;
    Vdbe *v;



    /* Compute the complete text of the CREATE VIRTUAL TABLE statement */
    if( pEnd ){
      pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n;
    }
    zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken);








>
>







138336
138337
138338
138339
138340
138341
138342
138343
138344
138345
138346
138347
138348
138349
138350
138351
  */
  if( !db->init.busy ){
    char *zStmt;
    char *zWhere;
    int iDb;
    int iReg;
    Vdbe *v;

    sqlite3MayAbort(pParse);

    /* Compute the complete text of the CREATE VIRTUAL TABLE statement */
    if( pEnd ){
      pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n;
    }
    zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken);

136937
136938
136939
136940
136941
136942
136943
136944
136945
136946
136947
136948
136949
136950

136951
136952
136953
136954
136955
136956
136957
       "WHERE rowid=#%d",
      db->aDb[iDb].zDbSName, MASTER_NAME,
      pTab->zName,
      pTab->zName,
      zStmt,
      pParse->regRowid
    );
    sqlite3DbFree(db, zStmt);
    v = sqlite3GetVdbe(pParse);
    sqlite3ChangeCookie(pParse, iDb);

    sqlite3VdbeAddOp0(v, OP_Expire);
    zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
    sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);


    iReg = ++pParse->nMem;
    sqlite3VdbeLoadString(v, iReg, pTab->zName);
    sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
  }

  /* If we are rereading the sqlite_master table create the in-memory







<




|

>







138364
138365
138366
138367
138368
138369
138370

138371
138372
138373
138374
138375
138376
138377
138378
138379
138380
138381
138382
138383
138384
       "WHERE rowid=#%d",
      db->aDb[iDb].zDbSName, MASTER_NAME,
      pTab->zName,
      pTab->zName,
      zStmt,
      pParse->regRowid
    );

    v = sqlite3GetVdbe(pParse);
    sqlite3ChangeCookie(pParse, iDb);

    sqlite3VdbeAddOp0(v, OP_Expire);
    zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
    sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
    sqlite3DbFree(db, zStmt);

    iReg = ++pParse->nMem;
    sqlite3VdbeLoadString(v, iReg, pTab->zName);
    sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
  }

  /* If we are rereading the sqlite_master table create the in-memory
137040
137041
137042
137043
137044
137045
137046

137047
137048
137049
137050
137051
137052
137053
  if( !pVTable ){
    sqlite3OomFault(db);
    sqlite3DbFree(db, zModuleName);
    return SQLITE_NOMEM_BKPT;
  }
  pVTable->db = db;
  pVTable->pMod = pMod;


  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
  pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;

  /* Invoke the virtual table constructor */
  assert( &db->pVtabCtx );
  assert( xConstruct );







>







138467
138468
138469
138470
138471
138472
138473
138474
138475
138476
138477
138478
138479
138480
138481
  if( !pVTable ){
    sqlite3OomFault(db);
    sqlite3DbFree(db, zModuleName);
    return SQLITE_NOMEM_BKPT;
  }
  pVTable->db = db;
  pVTable->pMod = pMod;
  pVTable->eVtabRisk = SQLITE_VTABRISK_Normal;

  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
  pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;

  /* Invoke the virtual table constructor */
  assert( &db->pVtabCtx );
  assert( xConstruct );
137345
137346
137347
137348
137349
137350
137351

137352
137353
137354
137355
137356
137357
137358
137359
      assert( p->pVtab );
      if( p->pVtab->nRef>0 ){
        return SQLITE_LOCKED;
      }
    }
    p = vtabDisconnectAll(db, pTab);
    xDestroy = p->pMod->pModule->xDestroy;

    assert( xDestroy!=0 );  /* Checked before the virtual table is created */
    pTab->nTabRef++;
    rc = xDestroy(p->pVtab);
    /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
    if( rc==SQLITE_OK ){
      assert( pTab->pVTable==p && p->pNext==0 );
      p->pVtab = 0;
      pTab->pVTable = 0;







>
|







138773
138774
138775
138776
138777
138778
138779
138780
138781
138782
138783
138784
138785
138786
138787
138788
      assert( p->pVtab );
      if( p->pVtab->nRef>0 ){
        return SQLITE_LOCKED;
      }
    }
    p = vtabDisconnectAll(db, pTab);
    xDestroy = p->pMod->pModule->xDestroy;
    if( xDestroy==0 ) xDestroy = p->pMod->pModule->xDisconnect;
    assert( xDestroy!=0 );
    pTab->nTabRef++;
    rc = xDestroy(p->pVtab);
    /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
    if( rc==SQLITE_OK ){
      assert( pTab->pVTable==p && p->pNext==0 );
      p->pVtab = 0;
      pTab->pVTable = 0;
137728
137729
137730
137731
137732
137733
137734

137735
137736
137737
137738
137739
137740
137741
137742
137743
137744
137745
137746
137747



137748

137749


137750
137751




137752
137753
137754
137755

137756

137757
137758
137759
137760
137761
137762
137763
** Call from within the xCreate() or xConnect() methods to provide 
** the SQLite core with additional information about the behavior
** of the virtual table being implemented.
*/
SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
  va_list ap;
  int rc = SQLITE_OK;


#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
  sqlite3_mutex_enter(db->mutex);
  va_start(ap, op);
  switch( op ){
    case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
      VtabCtx *p = db->pVtabCtx;
      if( !p ){
        rc = SQLITE_MISUSE_BKPT;
      }else{
        assert( p->pTab==0 || IsVirtual(p->pTab) );



        p->pVTable->bConstraint = (u8)va_arg(ap, int);

      }


      break;
    }




    default:
      rc = SQLITE_MISUSE_BKPT;
      break;
  }

  va_end(ap);


  if( rc!=SQLITE_OK ) sqlite3Error(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

#endif /* SQLITE_OMIT_VIRTUALTABLE */







>





<
<
<
|
|
|
|
|
>
>
>

>

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







139157
139158
139159
139160
139161
139162
139163
139164
139165
139166
139167
139168
139169



139170
139171
139172
139173
139174
139175
139176
139177
139178
139179
139180
139181
139182
139183
139184
139185
139186
139187
139188
139189
139190
139191
139192
139193
139194
139195
139196
139197
139198
139199
139200
139201
139202
** Call from within the xCreate() or xConnect() methods to provide 
** the SQLite core with additional information about the behavior
** of the virtual table being implemented.
*/
SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
  va_list ap;
  int rc = SQLITE_OK;
  VtabCtx *p;

#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
  sqlite3_mutex_enter(db->mutex);



  p = db->pVtabCtx;
  if( !p ){
    rc = SQLITE_MISUSE_BKPT;
  }else{
    assert( p->pTab==0 || IsVirtual(p->pTab) );
    va_start(ap, op);
    switch( op ){
      case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
        p->pVTable->bConstraint = (u8)va_arg(ap, int);
        break;
      }
      case SQLITE_VTAB_INNOCUOUS: {
        p->pVTable->eVtabRisk = SQLITE_VTABRISK_Low;
        break;
      }
      case SQLITE_VTAB_DIRECTONLY: {
        p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
        break;
      }
      default: {
        rc = SQLITE_MISUSE_BKPT;
        break;
      }
    }
    va_end(ap);
  }

  if( rc!=SQLITE_OK ) sqlite3Error(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

#endif /* SQLITE_OMIT_VIRTUALTABLE */
138058
138059
138060
138061
138062
138063
138064
138065
138066
138067
138068
138069
138070
138071
138072
138073
138074
138075
138076
138077
138078
138079
138080
138081






138082
138083
138084
138085
138086
138087
138088
  Bitmask prereqRight;    /* Bitmask of tables used by pExpr->pRight */
  Bitmask prereqAll;      /* Bitmask of tables referenced by pExpr */
};

/*
** Allowed values of WhereTerm.wtFlags
*/
#define TERM_DYNAMIC    0x01   /* Need to call sqlite3ExprDelete(db, pExpr) */
#define TERM_VIRTUAL    0x02   /* Added by the optimizer.  Do not code */
#define TERM_CODED      0x04   /* This term is already coded */
#define TERM_COPIED     0x08   /* Has a child */
#define TERM_ORINFO     0x10   /* Need to free the WhereTerm.u.pOrInfo object */
#define TERM_ANDINFO    0x20   /* Need to free the WhereTerm.u.pAndInfo obj */
#define TERM_OR_OK      0x40   /* Used during OR-clause processing */
#ifdef SQLITE_ENABLE_STAT4
#  define TERM_VNULL    0x80   /* Manufactured x>NULL or x<=NULL term */
#else
#  define TERM_VNULL    0x00   /* Disabled if not using stat4 */
#endif
#define TERM_LIKEOPT    0x100  /* Virtual terms from the LIKE optimization */
#define TERM_LIKECOND   0x200  /* Conditionally this LIKE operator term */
#define TERM_LIKE       0x400  /* The original LIKE operator */
#define TERM_IS         0x800  /* Term.pExpr is an IS operator */
#define TERM_VARSELECT  0x1000 /* Term.pExpr contains a correlated sub-query */







/*
** An instance of the WhereScan object is used as an iterator for locating
** terms in the WHERE clause that are useful to the query planner.
*/
struct WhereScan {
  WhereClause *pOrigWC;      /* Original, innermost WhereClause */







|
|
|
|
|
|
|

|

|

|
|
|
|

>
>
>
>
>
>







139497
139498
139499
139500
139501
139502
139503
139504
139505
139506
139507
139508
139509
139510
139511
139512
139513
139514
139515
139516
139517
139518
139519
139520
139521
139522
139523
139524
139525
139526
139527
139528
139529
139530
139531
139532
139533
  Bitmask prereqRight;    /* Bitmask of tables used by pExpr->pRight */
  Bitmask prereqAll;      /* Bitmask of tables referenced by pExpr */
};

/*
** Allowed values of WhereTerm.wtFlags
*/
#define TERM_DYNAMIC    0x0001 /* Need to call sqlite3ExprDelete(db, pExpr) */
#define TERM_VIRTUAL    0x0002 /* Added by the optimizer.  Do not code */
#define TERM_CODED      0x0004 /* This term is already coded */
#define TERM_COPIED     0x0008 /* Has a child */
#define TERM_ORINFO     0x0010 /* Need to free the WhereTerm.u.pOrInfo object */
#define TERM_ANDINFO    0x0020 /* Need to free the WhereTerm.u.pAndInfo obj */
#define TERM_OR_OK      0x0040 /* Used during OR-clause processing */
#ifdef SQLITE_ENABLE_STAT4
#  define TERM_VNULL    0x0080 /* Manufactured x>NULL or x<=NULL term */
#else
#  define TERM_VNULL    0x0000 /* Disabled if not using stat4 */
#endif
#define TERM_LIKEOPT    0x0100 /* Virtual terms from the LIKE optimization */
#define TERM_LIKECOND   0x0200 /* Conditionally this LIKE operator term */
#define TERM_LIKE       0x0400 /* The original LIKE operator */
#define TERM_IS         0x0800 /* Term.pExpr is an IS operator */
#define TERM_VARSELECT  0x1000 /* Term.pExpr contains a correlated sub-query */
#define TERM_HEURTRUTH  0x2000 /* Heuristic truthProb used */
#ifdef SQLITE_ENABLE_STAT4
#  define TERM_HIGHTRUTH  0x4000 /* Term excludes few rows */
#else
#  define TERM_HIGHTRUTH  0      /* Only used with STAT4 */
#endif

/*
** An instance of the WhereScan object is used as an iterator for locating
** terms in the WHERE clause that are useful to the query planner.
*/
struct WhereScan {
  WhereClause *pOrigWC;      /* Original, innermost WhereClause */
138189
138190
138191
138192
138193
138194
138195
138196

138197
138198
138199
138200
138201
138202


138203
138204
138205
138206
138207
138208
138209
  ExprList *pOrderBy;       /* ORDER BY clause */
  WhereLoop *pNew;          /* Template WhereLoop */
  WhereOrSet *pOrSet;       /* Record best loops here, if not NULL */
#ifdef SQLITE_ENABLE_STAT4
  UnpackedRecord *pRec;     /* Probe for stat4 (if required) */
  int nRecValid;            /* Number of valid fields currently in pRec */
#endif
  unsigned int bldFlags;    /* SQLITE_BLDF_* flags */

  unsigned int iPlanLimit;  /* Search limiter */
};

/* Allowed values for WhereLoopBuider.bldFlags */
#define SQLITE_BLDF_INDEXED  0x0001   /* An index is used */
#define SQLITE_BLDF_UNIQUE   0x0002   /* All keys of a UNIQUE index used */



/* The WhereLoopBuilder.iPlanLimit is used to limit the number of
** index+constraint combinations the query planner will consider for a
** particular query.  If this parameter is unlimited, then certain
** pathological queries can spend excess time in the sqlite3WhereBegin()
** routine.  The limit is high enough that is should not impact real-world
** queries.







|
>




|
|
>
>







139634
139635
139636
139637
139638
139639
139640
139641
139642
139643
139644
139645
139646
139647
139648
139649
139650
139651
139652
139653
139654
139655
139656
139657
  ExprList *pOrderBy;       /* ORDER BY clause */
  WhereLoop *pNew;          /* Template WhereLoop */
  WhereOrSet *pOrSet;       /* Record best loops here, if not NULL */
#ifdef SQLITE_ENABLE_STAT4
  UnpackedRecord *pRec;     /* Probe for stat4 (if required) */
  int nRecValid;            /* Number of valid fields currently in pRec */
#endif
  unsigned char bldFlags1;  /* First set of SQLITE_BLDF_* flags */
  unsigned char bldFlags2;  /* Second set of SQLITE_BLDF_* flags */
  unsigned int iPlanLimit;  /* Search limiter */
};

/* Allowed values for WhereLoopBuider.bldFlags */
#define SQLITE_BLDF1_INDEXED  0x0001   /* An index is used */
#define SQLITE_BLDF1_UNIQUE   0x0002   /* All keys of a UNIQUE index used */

#define SQLITE_BLDF2_2NDPASS  0x0004   /* Second builder pass needed */

/* The WhereLoopBuilder.iPlanLimit is used to limit the number of
** index+constraint combinations the query planner will consider for a
** particular query.  If this parameter is unlimited, then certain
** pathological queries can spend excess time in the sqlite3WhereBegin()
** routine.  The limit is high enough that is should not impact real-world
** queries.
138217
138218
138219
138220
138221
138222
138223














138224
138225
138226
138227
138228
138229
138230
138231
138232
138233
138234
138235
138236
138237
138238
138239
138240
138241
138242
138243
138244
138245

138246
138247
138248
138249
138250
138251


138252


138253
138254

138255
138256
138257
138258
138259
138260
138261
138262
138263
138264
138265
138266
138267
138268
138269


138270
138271
138272
138273
138274
138275
138276
#ifndef SQLITE_QUERY_PLANNER_LIMIT
# define SQLITE_QUERY_PLANNER_LIMIT 20000
#endif
#ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR
# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000
#endif















/*
** The WHERE clause processing routine has two halves.  The
** first part does the start of the WHERE loop and the second
** half does the tail of the WHERE loop.  An instance of
** this structure is returned by the first half and passed
** into the second half to give some continuity.
**
** An instance of this object holds the complete state of the query
** planner.
*/
struct WhereInfo {
  Parse *pParse;            /* Parsing and code generating context */
  SrcList *pTabList;        /* List of tables in the join */
  ExprList *pOrderBy;       /* The ORDER BY clause or NULL */
  ExprList *pResultSet;     /* Result set of the query */
  Expr *pWhere;             /* The complete WHERE clause */
  LogEst iLimit;            /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
  int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
  int iContinue;            /* Jump here to continue with next record */
  int iBreak;               /* Jump here to break out of the loop */
  int savedNQueryLoop;      /* pParse->nQueryLoop outside the WHERE loop */
  u16 wctrlFlags;           /* Flags originally passed to sqlite3WhereBegin() */

  u8 nLevel;                /* Number of nested loop */
  i8 nOBSat;                /* Number of ORDER BY terms satisfied by indices */
  u8 sorted;                /* True if really sorted (not just grouped) */
  u8 eOnePass;              /* ONEPASS_OFF, or _SINGLE, or _MULTI */
  u8 untestedTerms;         /* Not all WHERE terms resolved by outer loop */
  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values */


  u8 bOrderedInnerLoop;     /* True if only the inner-most loop is ordered */


  int iTop;                 /* The very beginning of the WHERE loop */
  WhereLoop *pLoops;        /* List of all WhereLoop objects */

  Bitmask revMask;          /* Mask of ORDER BY terms that need reversing */
  LogEst nRowOut;           /* Estimated number of output rows */
  WhereClause sWC;          /* Decomposition of the WHERE clause */
  WhereMaskSet sMaskSet;    /* Map cursor numbers to bitmasks */
  WhereLevel a[1];          /* Information about each nest loop in WHERE */
};

/*
** Private interfaces - callable only by other where.c routines.
**
** where.c:
*/
SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
#ifdef WHERETRACE_ENABLED
SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC);


#endif
SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
  WhereClause *pWC,     /* The WHERE clause to be searched */
  int iCur,             /* Cursor number of LHS */
  int iColumn,          /* Column number of LHS */
  Bitmask notReady,     /* RHS must not overlap with this mask */
  u32 op,               /* Mask of WO_xx values describing operator */







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
















<





>


<

<

>
>
|
>
>


>

<













>
>







139665
139666
139667
139668
139669
139670
139671
139672
139673
139674
139675
139676
139677
139678
139679
139680
139681
139682
139683
139684
139685
139686
139687
139688
139689
139690
139691
139692
139693
139694
139695
139696
139697
139698
139699
139700
139701

139702
139703
139704
139705
139706
139707
139708
139709

139710

139711
139712
139713
139714
139715
139716
139717
139718
139719
139720

139721
139722
139723
139724
139725
139726
139727
139728
139729
139730
139731
139732
139733
139734
139735
139736
139737
139738
139739
139740
139741
139742
#ifndef SQLITE_QUERY_PLANNER_LIMIT
# define SQLITE_QUERY_PLANNER_LIMIT 20000
#endif
#ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR
# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000
#endif

/*
** Each instance of this object records a change to a single node
** in an expression tree to cause that node to point to a column
** of an index rather than an expression or a virtual column.  All
** such transformations need to be undone at the end of WHERE clause
** processing.
*/
typedef struct WhereExprMod WhereExprMod;
struct WhereExprMod {
  WhereExprMod *pNext;  /* Next translation on a list of them all */
  Expr *pExpr;          /* The Expr node that was transformed */
  Expr orig;            /* Original value of the Expr node */
};

/*
** The WHERE clause processing routine has two halves.  The
** first part does the start of the WHERE loop and the second
** half does the tail of the WHERE loop.  An instance of
** this structure is returned by the first half and passed
** into the second half to give some continuity.
**
** An instance of this object holds the complete state of the query
** planner.
*/
struct WhereInfo {
  Parse *pParse;            /* Parsing and code generating context */
  SrcList *pTabList;        /* List of tables in the join */
  ExprList *pOrderBy;       /* The ORDER BY clause or NULL */
  ExprList *pResultSet;     /* Result set of the query */
  Expr *pWhere;             /* The complete WHERE clause */

  int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
  int iContinue;            /* Jump here to continue with next record */
  int iBreak;               /* Jump here to break out of the loop */
  int savedNQueryLoop;      /* pParse->nQueryLoop outside the WHERE loop */
  u16 wctrlFlags;           /* Flags originally passed to sqlite3WhereBegin() */
  LogEst iLimit;            /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
  u8 nLevel;                /* Number of nested loop */
  i8 nOBSat;                /* Number of ORDER BY terms satisfied by indices */

  u8 eOnePass;              /* ONEPASS_OFF, or _SINGLE, or _MULTI */

  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values */
  unsigned bDeferredSeek :1;   /* Uses OP_DeferredSeek */
  unsigned untestedTerms :1;   /* Not all WHERE terms resolved by outer loop */
  unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */
  unsigned sorted :1;          /* True if really sorted (not just grouped) */
  LogEst nRowOut;           /* Estimated number of output rows */
  int iTop;                 /* The very beginning of the WHERE loop */
  WhereLoop *pLoops;        /* List of all WhereLoop objects */
  WhereExprMod *pExprMods;  /* Expression modifications */
  Bitmask revMask;          /* Mask of ORDER BY terms that need reversing */

  WhereClause sWC;          /* Decomposition of the WHERE clause */
  WhereMaskSet sMaskSet;    /* Map cursor numbers to bitmasks */
  WhereLevel a[1];          /* Information about each nest loop in WHERE */
};

/*
** Private interfaces - callable only by other where.c routines.
**
** where.c:
*/
SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
#ifdef WHERETRACE_ENABLED
SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC);
SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm);
SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC);
#endif
SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
  WhereClause *pWC,     /* The WHERE clause to be searched */
  int iCur,             /* Cursor number of LHS */
  int iColumn,          /* Column number of LHS */
  Bitmask notReady,     /* RHS must not overlap with this mask */
  u32 op,               /* Mask of WO_xx values describing operator */
138774
138775
138776
138777
138778
138779
138780

138781
138782
138783
138784
138785
138786
138787
138788
static Expr *removeUnindexableInClauseTerms(
  Parse *pParse,        /* The parsing context */
  int iEq,              /* Look at loop terms starting here */
  WhereLoop *pLoop,     /* The current loop */
  Expr *pX              /* The IN expression to be reduced */
){
  sqlite3 *db = pParse->db;

  Expr *pNew = sqlite3ExprDup(db, pX, 0);
  if( db->mallocFailed==0 ){
    ExprList *pOrigRhs = pNew->x.pSelect->pEList;  /* Original unmodified RHS */
    ExprList *pOrigLhs = pNew->pLeft->x.pList;     /* Original unmodified LHS */
    ExprList *pRhs = 0;         /* New RHS after modifications */
    ExprList *pLhs = 0;         /* New LHS after mods */
    int i;                      /* Loop counter */
    Select *pSelect;            /* Pointer to the SELECT on the RHS */







>
|







140240
140241
140242
140243
140244
140245
140246
140247
140248
140249
140250
140251
140252
140253
140254
140255
static Expr *removeUnindexableInClauseTerms(
  Parse *pParse,        /* The parsing context */
  int iEq,              /* Look at loop terms starting here */
  WhereLoop *pLoop,     /* The current loop */
  Expr *pX              /* The IN expression to be reduced */
){
  sqlite3 *db = pParse->db;
  Expr *pNew;
  pNew = sqlite3ExprDup(db, pX, 0);
  if( db->mallocFailed==0 ){
    ExprList *pOrigRhs = pNew->x.pSelect->pEList;  /* Original unmodified RHS */
    ExprList *pOrigLhs = pNew->pLeft->x.pList;     /* Original unmodified LHS */
    ExprList *pRhs = 0;         /* New RHS after modifications */
    ExprList *pLhs = 0;         /* New LHS after mods */
    int i;                      /* Loop counter */
    Select *pSelect;            /* Pointer to the SELECT on the RHS */
138951
138952
138953
138954
138955
138956
138957
138958
138959
138960
138961
138962
138963
138964
138965
            int iCol = aiMap ? aiMap[iMap++] : 0;
            pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
          }
          sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
          if( i==iEq ){
            pIn->iCur = iTab;
            pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
            if( iEq>0 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){
              pIn->iBase = iReg - i;
              pIn->nPrefix = i;
              pLoop->wsFlags |= WHERE_IN_EARLYOUT;
            }else{
              pIn->nPrefix = 0;
            }
          }else{







|







140418
140419
140420
140421
140422
140423
140424
140425
140426
140427
140428
140429
140430
140431
140432
            int iCol = aiMap ? aiMap[iMap++] : 0;
            pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
          }
          sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
          if( i==iEq ){
            pIn->iCur = iTab;
            pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
            if( iEq>0 ){
              pIn->iBase = iReg - i;
              pIn->nPrefix = i;
              pLoop->wsFlags |= WHERE_IN_EARLYOUT;
            }else{
              pIn->nPrefix = 0;
            }
          }else{
139403
139404
139405
139406
139407
139408
139409

139410
139411
139412
139413
139414
139415
139416
){
  Parse *pParse = pWInfo->pParse; /* Parse context */
  Vdbe *v = pParse->pVdbe;        /* Vdbe to generate code within */

  assert( iIdxCur>0 );
  assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
  

  sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
  if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
   && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
  ){
    int i;
    Table *pTab = pIdx->pTable;
    int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));







>







140870
140871
140872
140873
140874
140875
140876
140877
140878
140879
140880
140881
140882
140883
140884
){
  Parse *pParse = pWInfo->pParse; /* Parse context */
  Vdbe *v = pParse->pVdbe;        /* Vdbe to generate code within */

  assert( iIdxCur>0 );
  assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
  
  pWInfo->bDeferredSeek = 1;
  sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
  if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
   && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
  ){
    int i;
    Table *pTab = pIdx->pTable;
    int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
139470
139471
139472
139473
139474
139475
139476


139477













139478
139479
139480
139481
139482
139483
139484
139485
139486
139487

139488
139489
139490
139491
139492



139493
139494
139495
139496
139497
139498
139499
139500
139501
139502
139503
139504
139505
139506



139507
139508
139509
139510
139511
139512
139513
*/
typedef struct IdxExprTrans {
  Expr *pIdxExpr;    /* The index expression */
  int iTabCur;       /* The cursor of the corresponding table */
  int iIdxCur;       /* The cursor for the index */
  int iIdxCol;       /* The column for the index */
  int iTabCol;       /* The column for the table */


} IdxExprTrans;














/* The walker node callback used to transform matching expressions into
** a reference to an index column for an index on an expression.
**
** If pExpr matches, then transform it into a reference to the index column
** that contains the value of pExpr.
*/
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
  IdxExprTrans *pX = p->u.pIdxTrans;
  if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){

    pExpr->affExpr = sqlite3ExprAffinity(pExpr);
    pExpr->op = TK_COLUMN;
    pExpr->iTable = pX->iIdxCur;
    pExpr->iColumn = pX->iIdxCol;
    pExpr->y.pTab = 0;



    return WRC_Prune;
  }else{
    return WRC_Continue;
  }
}

#ifndef SQLITE_OMIT_GENERATED_COLUMNS
/* A walker node callback that translates a column reference to a table
** into a corresponding column reference of an index.
*/
static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
  if( pExpr->op==TK_COLUMN ){
    IdxExprTrans *pX = p->u.pIdxTrans;
    if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){



      pExpr->iTable = pX->iIdxCur;
      pExpr->iColumn = pX->iIdxCol;
      pExpr->y.pTab = 0;
    }
  }
  return WRC_Continue;
}







>
>

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










>





>
>
>














>
>
>







140938
140939
140940
140941
140942
140943
140944
140945
140946
140947
140948
140949
140950
140951
140952
140953
140954
140955
140956
140957
140958
140959
140960
140961
140962
140963
140964
140965
140966
140967
140968
140969
140970
140971
140972
140973
140974
140975
140976
140977
140978
140979
140980
140981
140982
140983
140984
140985
140986
140987
140988
140989
140990
140991
140992
140993
140994
140995
140996
140997
140998
140999
141000
141001
141002
141003
*/
typedef struct IdxExprTrans {
  Expr *pIdxExpr;    /* The index expression */
  int iTabCur;       /* The cursor of the corresponding table */
  int iIdxCur;       /* The cursor for the index */
  int iIdxCol;       /* The column for the index */
  int iTabCol;       /* The column for the table */
  WhereInfo *pWInfo; /* Complete WHERE clause information */
  sqlite3 *db;       /* Database connection (for malloc()) */
} IdxExprTrans;

/*
** Preserve pExpr on the WhereETrans list of the WhereInfo.
*/
static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
  WhereExprMod *pNew;
  pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew));
  if( pNew==0 ) return;
  pNew->pNext = pTrans->pWInfo->pExprMods;
  pTrans->pWInfo->pExprMods = pNew;
  pNew->pExpr = pExpr;
  memcpy(&pNew->orig, pExpr, sizeof(*pExpr));
}

/* The walker node callback used to transform matching expressions into
** a reference to an index column for an index on an expression.
**
** If pExpr matches, then transform it into a reference to the index column
** that contains the value of pExpr.
*/
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
  IdxExprTrans *pX = p->u.pIdxTrans;
  if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
    preserveExpr(pX, pExpr);
    pExpr->affExpr = sqlite3ExprAffinity(pExpr);
    pExpr->op = TK_COLUMN;
    pExpr->iTable = pX->iIdxCur;
    pExpr->iColumn = pX->iIdxCol;
    pExpr->y.pTab = 0;
    testcase( ExprHasProperty(pExpr, EP_Skip) );
    testcase( ExprHasProperty(pExpr, EP_Unlikely) );
    ExprClearProperty(pExpr, EP_Skip|EP_Unlikely);
    return WRC_Prune;
  }else{
    return WRC_Continue;
  }
}

#ifndef SQLITE_OMIT_GENERATED_COLUMNS
/* A walker node callback that translates a column reference to a table
** into a corresponding column reference of an index.
*/
static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
  if( pExpr->op==TK_COLUMN ){
    IdxExprTrans *pX = p->u.pIdxTrans;
    if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
      assert( pExpr->y.pTab!=0 );
      preserveExpr(pX, pExpr);
      pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn);
      pExpr->iTable = pX->iIdxCur;
      pExpr->iColumn = pX->iIdxCol;
      pExpr->y.pTab = 0;
    }
  }
  return WRC_Continue;
}
139540
139541
139542
139543
139544
139545
139546


139547
139548
139549
139550
139551

139552
139553

139554









139555
139556
139557
139558
139559
139560
139561
    return;
  }
  pTab = pIdx->pTable;
  memset(&w, 0, sizeof(w));
  w.u.pIdxTrans = &x;
  x.iTabCur = iTabCur;
  x.iIdxCur = iIdxCur;


  for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
    i16 iRef = pIdx->aiColumn[iIdxCol];
    if( iRef==XN_EXPR ){
      assert( aColExpr->a[iIdxCol].pExpr!=0 );
      x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;

      w.xExprCallback = whereIndexExprTransNode;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS

    }else if( iRef>=0 && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0 ){









      x.iTabCol = iRef;
      w.xExprCallback = whereIndexExprTransColumn;
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
    }else{
      continue;
    }
    x.iIdxCol = iIdxCol;







>
>





>


>
|
>
>
>
>
>
>
>
>
>







141030
141031
141032
141033
141034
141035
141036
141037
141038
141039
141040
141041
141042
141043
141044
141045
141046
141047
141048
141049
141050
141051
141052
141053
141054
141055
141056
141057
141058
141059
141060
141061
141062
141063
141064
    return;
  }
  pTab = pIdx->pTable;
  memset(&w, 0, sizeof(w));
  w.u.pIdxTrans = &x;
  x.iTabCur = iTabCur;
  x.iIdxCur = iIdxCur;
  x.pWInfo = pWInfo;
  x.db = pWInfo->pParse->db;
  for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
    i16 iRef = pIdx->aiColumn[iIdxCol];
    if( iRef==XN_EXPR ){
      assert( aColExpr->a[iIdxCol].pExpr!=0 );
      x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
      if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
      w.xExprCallback = whereIndexExprTransNode;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
    }else if( iRef>=0
       && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
       && (pTab->aCol[iRef].zColl==0
           || sqlite3StrICmp(pTab->aCol[iRef].zColl, sqlite3StrBINARY)==0)
    ){
      /* Check to see if there are direct references to generated columns
      ** that are contained in the index.  Pulling the generated column
      ** out of the index is an optimization only - the main table is always
      ** available if the index cannot be used.  To avoid unnecessary
      ** complication, omit this optimization if the collating sequence for
      ** the column is non-standard */
      x.iTabCol = iRef;
      w.xExprCallback = whereIndexExprTransColumn;
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
    }else{
      continue;
    }
    x.iIdxCol = iIdxCol;
139626
139627
139628
139629
139630
139631
139632















139633
139634
139635
139636
139637
139638
139639
  db = pParse->db;
  pLoop = pLevel->pWLoop;
  pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
  iCur = pTabItem->iCursor;
  pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
  bRev = (pWInfo->revMask>>iLevel)&1;
  VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
















  /* Create labels for the "break" and "continue" instructions
  ** for the current loop.  Jump to addrBrk to break out of a loop.
  ** Jump to cont to go immediately to the next iteration of the
  ** loop.
  **
  ** When there is an IN operator, we also have a "addrNxt" label that







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







141129
141130
141131
141132
141133
141134
141135
141136
141137
141138
141139
141140
141141
141142
141143
141144
141145
141146
141147
141148
141149
141150
141151
141152
141153
141154
141155
141156
141157
  db = pParse->db;
  pLoop = pLevel->pWLoop;
  pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
  iCur = pTabItem->iCursor;
  pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
  bRev = (pWInfo->revMask>>iLevel)&1;
  VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
#if WHERETRACE_ENABLED /* 0x20800 */
  if( sqlite3WhereTrace & 0x800 ){
    sqlite3DebugPrintf("Coding level %d of %d:  notReady=%llx  iFrom=%d\n",
       iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
    sqlite3WhereLoopPrint(pLoop, pWC);
  }
  if( sqlite3WhereTrace & 0x20000 ){
    if( iLevel==0 ){
      sqlite3DebugPrintf("WHERE clause being coded:\n");
      sqlite3TreeViewExpr(0, pWInfo->pWhere, 0);
    }
    sqlite3DebugPrintf("All WHERE-clause terms before coding:\n");
    sqlite3WhereClausePrint(pWC);
  }
#endif

  /* Create labels for the "break" and "continue" instructions
  ** for the current loop.  Jump to addrBrk to break out of a loop.
  ** Jump to cont to go immediately to the next iteration of the
  ** loop.
  **
  ** When there is an IN operator, we also have a "addrNxt" label that
139739
139740
139741
139742
139743
139744
139745
139746


139747
139748
139749
139750
139751
139752
139753
        pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
        assert( pCompare!=0 || db->mallocFailed );
        if( pCompare ){
          pCompare->pLeft = pTerm->pExpr->pLeft;
          pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
          if( pRight ){
            pRight->iTable = iReg+j+2;
            sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);


          }
          pCompare->pLeft = 0;
          sqlite3ExprDelete(db, pCompare);
        }
      }
    }
    assert( iIn==0 || db->mallocFailed );







|
>
>







141257
141258
141259
141260
141261
141262
141263
141264
141265
141266
141267
141268
141269
141270
141271
141272
141273
        pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
        assert( pCompare!=0 || db->mallocFailed );
        if( pCompare ){
          pCompare->pLeft = pTerm->pExpr->pLeft;
          pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
          if( pRight ){
            pRight->iTable = iReg+j+2;
            sqlite3ExprIfFalse(
                pParse, pCompare, pLevel->addrCont, SQLITE_JUMPIFNULL
            );
          }
          pCompare->pLeft = 0;
          sqlite3ExprDelete(db, pCompare);
        }
      }
    }
    assert( iIn==0 || db->mallocFailed );
140012
140013
140014
140015
140016
140017
140018
140019
140020
140021
140022



140023
140024
140025
140026
140027
140028
140029
    ** For DESC, NULL entries are scanned first.
    */
    if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0
     && (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0
    ){
      assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 );
      assert( pRangeEnd==0 && pRangeStart==0 );
      assert( pLoop->nSkip==0 );
      nExtraReg = 1;
      bSeekPastNull = 1;
      pLevel->regBignull = regBignull = ++pParse->nMem;



      pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse);
    }

    /* If we are doing a reverse order scan on an ascending index, or
    ** a forward order scan on a descending index, interchange the 
    ** start and end terms (pRangeStart and pRangeEnd).
    */







|



>
>
>







141532
141533
141534
141535
141536
141537
141538
141539
141540
141541
141542
141543
141544
141545
141546
141547
141548
141549
141550
141551
141552
    ** For DESC, NULL entries are scanned first.
    */
    if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0
     && (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0
    ){
      assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 );
      assert( pRangeEnd==0 && pRangeStart==0 );
      testcase( pLoop->nSkip>0 );
      nExtraReg = 1;
      bSeekPastNull = 1;
      pLevel->regBignull = regBignull = ++pParse->nMem;
      if( pLevel->iLeftJoin ){
        sqlite3VdbeAddOp2(v, OP_Integer, 0, regBignull);
      }
      pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse);
    }

    /* If we are doing a reverse order scan on an ascending index, or
    ** a forward order scan on a descending index, interchange the 
    ** start and end terms (pRangeStart and pRangeEnd).
    */
140211
140212
140213
140214
140215
140216
140217
140218
140219
140220
140221
140222
140223
140224
140225
140226
140227
140228

    /* Seek the table cursor, if required */
    omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 
           && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
    if( omitTable ){
      /* pIdx is a covering index.  No need to access the main table. */
    }else if( HasRowid(pIdx->pTable) ){
      if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || (
          (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) 
       && (pWInfo->eOnePass==ONEPASS_SINGLE)
      )){
        iRowidReg = ++pParse->nMem;
        sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
        sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
        VdbeCoverage(v);
      }else{
        codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
      }







|
|
|
|







141734
141735
141736
141737
141738
141739
141740
141741
141742
141743
141744
141745
141746
141747
141748
141749
141750
141751

    /* Seek the table cursor, if required */
    omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 
           && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
    if( omitTable ){
      /* pIdx is a covering index.  No need to access the main table. */
    }else if( HasRowid(pIdx->pTable) ){
      if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)
       || ( (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE)!=0
           && (pWInfo->eOnePass==ONEPASS_SINGLE || pLoop->nLTerm==0) )
      ){
        iRowidReg = ++pParse->nMem;
        sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
        sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
        VdbeCoverage(v);
      }else{
        codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
      }
140457
140458
140459
140460
140461
140462
140463
140464
140465
140466
140467
140468
140469
140470
140471
140472
140473
    ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR"));
    for(ii=0; ii<pOrWc->nTerm; ii++){
      WhereTerm *pOrTerm = &pOrWc->a[ii];
      if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
        WhereInfo *pSubWInfo;           /* Info for single OR-term scan */
        Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
        int jmp1 = 0;                   /* Address of jump operation */
        assert( (pTabItem[0].fg.jointype & JT_LEFT)==0 
             || ExprHasProperty(pOrExpr, EP_FromJoin) 
        );
        if( pAndExpr ){
          pAndExpr->pLeft = pOrExpr;
          pOrExpr = pAndExpr;
        }
        /* Loop through table entries that match term pOrTerm. */
        ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
        WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));







|
|
|







141980
141981
141982
141983
141984
141985
141986
141987
141988
141989
141990
141991
141992
141993
141994
141995
141996
    ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR"));
    for(ii=0; ii<pOrWc->nTerm; ii++){
      WhereTerm *pOrTerm = &pOrWc->a[ii];
      if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
        WhereInfo *pSubWInfo;           /* Info for single OR-term scan */
        Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
        int jmp1 = 0;                   /* Address of jump operation */
        testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0
               && !ExprHasProperty(pOrExpr, EP_FromJoin)
        ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */
        if( pAndExpr ){
          pAndExpr->pLeft = pOrExpr;
          pOrExpr = pAndExpr;
        }
        /* Loop through table entries that match term pOrTerm. */
        ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
        WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
140681
140682
140683
140684
140685
140686
140687




140688
140689
140690
140691
140692
140693
140694
#endif
      }
#ifdef WHERETRACE_ENABLED /* 0xffff */
      if( sqlite3WhereTrace ){
        VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
                         pWC->nTerm-j, pTerm, iLoop));
      }




#endif
      sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
      if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
      pTerm->wtFlags |= TERM_CODED;
    }
    iLoop = iNext;
  }while( iLoop>0 );







>
>
>
>







142204
142205
142206
142207
142208
142209
142210
142211
142212
142213
142214
142215
142216
142217
142218
142219
142220
142221
#endif
      }
#ifdef WHERETRACE_ENABLED /* 0xffff */
      if( sqlite3WhereTrace ){
        VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
                         pWC->nTerm-j, pTerm, iLoop));
      }
      if( sqlite3WhereTrace & 0x800 ){
        sqlite3DebugPrintf("Coding auxiliary constraint:\n");
        sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
      }
#endif
      sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
      if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
      pTerm->wtFlags |= TERM_CODED;
    }
    iLoop = iNext;
  }while( iLoop>0 );
140704
140705
140706
140707
140708
140709
140710
140711
140712






140713
140714
140715
140716
140717
140718
140719
  for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
    Expr *pE, sEAlt;
    WhereTerm *pAlt;
    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
    if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
    if( pTerm->leftCursor!=iCur ) continue;
    if( pLevel->iLeftJoin ) continue;
    pE = pTerm->pExpr;






    assert( !ExprHasProperty(pE, EP_FromJoin) );
    assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
    pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady,
                    WO_EQ|WO_IN|WO_IS, 0);
    if( pAlt==0 ) continue;
    if( pAlt->wtFlags & (TERM_CODED) ) continue;
    if( (pAlt->eOperator & WO_IN) 







|

>
>
>
>
>
>







142231
142232
142233
142234
142235
142236
142237
142238
142239
142240
142241
142242
142243
142244
142245
142246
142247
142248
142249
142250
142251
142252
  for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
    Expr *pE, sEAlt;
    WhereTerm *pAlt;
    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
    if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
    if( pTerm->leftCursor!=iCur ) continue;
    if( pTabItem->fg.jointype & JT_LEFT ) continue;
    pE = pTerm->pExpr;
#ifdef WHERETRACE_ENABLED /* 0x800 */
    if( sqlite3WhereTrace & 0x800 ){
      sqlite3DebugPrintf("Coding transitive constraint:\n");
      sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
    }
#endif
    assert( !ExprHasProperty(pE, EP_FromJoin) );
    assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
    pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady,
                    WO_EQ|WO_IN|WO_IS, 0);
    if( pAlt==0 ) continue;
    if( pAlt->wtFlags & (TERM_CODED) ) continue;
    if( (pAlt->eOperator & WO_IN) 
140748
140749
140750
140751
140752
140753
140754











140755
140756
140757
140758
140759
140760
140761
      }
      assert( pTerm->pExpr );
      sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
      pTerm->wtFlags |= TERM_CODED;
    }
  }












  return pLevel->notReady;
}

/************** End of wherecode.c *******************************************/
/************** Begin file whereexpr.c ***************************************/
/*
** 2015-06-08







>
>
>
>
>
>
>
>
>
>
>







142281
142282
142283
142284
142285
142286
142287
142288
142289
142290
142291
142292
142293
142294
142295
142296
142297
142298
142299
142300
142301
142302
142303
142304
142305
      }
      assert( pTerm->pExpr );
      sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
      pTerm->wtFlags |= TERM_CODED;
    }
  }

#if WHERETRACE_ENABLED /* 0x20800 */
  if( sqlite3WhereTrace & 0x20000 ){
    sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
                       iLevel);
    sqlite3WhereClausePrint(pWC);
  }
  if( sqlite3WhereTrace & 0x800 ){
    sqlite3DebugPrintf("End Coding level %d:  notReady=%llx\n",
       iLevel, (u64)pLevel->notReady);
  }
#endif
  return pLevel->notReady;
}

/************** End of wherecode.c *******************************************/
/************** Begin file whereexpr.c ***************************************/
/*
** 2015-06-08
141132
141133
141134
141135
141136
141137
141138
141139

141140
141141
141142
141143
141144
141145
141146
    ** virtual table on their second argument, which is the same as
    ** the left-hand side operand in their in-fix form.
    **
    **       vtab_column MATCH expression
    **       MATCH(expression,vtab_column)
    */
    pCol = pList->a[1].pExpr;
    if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){

      for(i=0; i<ArraySize(aOp); i++){
        if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
          *peOp2 = aOp[i].eOp2;
          *ppRight = pList->a[0].pExpr;
          *ppLeft = pCol;
          return 1;
        }







|
>







142676
142677
142678
142679
142680
142681
142682
142683
142684
142685
142686
142687
142688
142689
142690
142691
    ** virtual table on their second argument, which is the same as
    ** the left-hand side operand in their in-fix form.
    **
    **       vtab_column MATCH expression
    **       MATCH(expression,vtab_column)
    */
    pCol = pList->a[1].pExpr;
    testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
    if( ExprIsVtab(pCol) ){
      for(i=0; i<ArraySize(aOp); i++){
        if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
          *peOp2 = aOp[i].eOp2;
          *ppRight = pList->a[0].pExpr;
          *ppLeft = pCol;
          return 1;
        }
141154
141155
141156
141157
141158
141159
141160
141161

141162
141163
141164
141165
141166
141167
141168
    **      OVERLOADED(vtab_column,expression)
    **
    ** Historically, xFindFunction expected to see lower-case function
    ** names.  But for this use case, xFindFunction is expected to deal
    ** with function names in an arbitrary case.
    */
    pCol = pList->a[0].pExpr;
    if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){

      sqlite3_vtab *pVtab;
      sqlite3_module *pMod;
      void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
      void *pNotUsed;
      pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
      assert( pVtab!=0 );
      assert( pVtab->pModule!=0 );







|
>







142699
142700
142701
142702
142703
142704
142705
142706
142707
142708
142709
142710
142711
142712
142713
142714
    **      OVERLOADED(vtab_column,expression)
    **
    ** Historically, xFindFunction expected to see lower-case function
    ** names.  But for this use case, xFindFunction is expected to deal
    ** with function names in an arbitrary case.
    */
    pCol = pList->a[0].pExpr;
    testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
    if( ExprIsVtab(pCol) ){
      sqlite3_vtab *pVtab;
      sqlite3_module *pMod;
      void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
      void *pNotUsed;
      pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
      assert( pVtab!=0 );
      assert( pVtab->pModule!=0 );
141177
141178
141179
141180
141181
141182
141183
141184

141185
141186
141187

141188
141189
141190
141191
141192
141193
141194
        }
      }
    }
  }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
    int res = 0;
    Expr *pLeft = pExpr->pLeft;
    Expr *pRight = pExpr->pRight;
    if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->y.pTab) ){

      res++;
    }
    if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->y.pTab) ){

      res++;
      SWAP(Expr*, pLeft, pRight);
    }
    *ppLeft = pLeft;
    *ppRight = pRight;
    if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
    if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT;







|
>


|
>







142723
142724
142725
142726
142727
142728
142729
142730
142731
142732
142733
142734
142735
142736
142737
142738
142739
142740
142741
142742
        }
      }
    }
  }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
    int res = 0;
    Expr *pLeft = pExpr->pLeft;
    Expr *pRight = pExpr->pRight;
    testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 );
    if( ExprIsVtab(pLeft) ){
      res++;
    }
    testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 );
    if( pRight && ExprIsVtab(pRight) ){
      res++;
      SWAP(Expr*, pLeft, pRight);
    }
    *ppLeft = pLeft;
    *ppRight = pRight;
    if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
    if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT;
142053
142054
142055
142056
142057
142058
142059

142060
142061
142062
142063
142064
142065
142066
      prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
      if( (prereqExpr & prereqColumn)==0 ){
        Expr *pNewExpr;
        pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 
            0, sqlite3ExprDup(db, pRight, 0));
        if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
          ExprSetProperty(pNewExpr, EP_FromJoin);

        }
        idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
        testcase( idxNew==0 );
        pNewTerm = &pWC->a[idxNew];
        pNewTerm->prereqRight = prereqExpr;
        pNewTerm->leftCursor = pLeft->iTable;
        pNewTerm->u.leftColumn = pLeft->iColumn;







>







143601
143602
143603
143604
143605
143606
143607
143608
143609
143610
143611
143612
143613
143614
143615
      prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
      if( (prereqExpr & prereqColumn)==0 ){
        Expr *pNewExpr;
        pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 
            0, sqlite3ExprDup(db, pRight, 0));
        if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
          ExprSetProperty(pNewExpr, EP_FromJoin);
          pNewExpr->iRightJoinTable = pExpr->iRightJoinTable;
        }
        idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
        testcase( idxNew==0 );
        pNewTerm = &pWC->a[idxNew];
        pNewTerm->prereqRight = prereqExpr;
        pNewTerm->leftCursor = pLeft->iTable;
        pNewTerm->u.leftColumn = pLeft->iColumn;
142109
142110
142111
142112
142113
142114
142115
142116

142117
142118
142119
142120



142121
142122
142123
142124
142125
142126
142127

  /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
  ** a virtual term for each vector component. The expression object
  ** used by each such virtual term is pExpr (the full vector IN(...) 
  ** expression). The WhereTerm.iField variable identifies the index within
  ** the vector on the LHS that the virtual term represents.
  **
  ** This only works if the RHS is a simple SELECT, not a compound

  */
  if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
   && pExpr->pLeft->op==TK_VECTOR
   && pExpr->x.pSelect->pPrior==0



  ){
    int i;
    for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
      int idxNew;
      idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
      pWC->a[idxNew].iField = i+1;
      exprAnalyze(pSrc, pWC, idxNew);







|
>




>
>
>







143658
143659
143660
143661
143662
143663
143664
143665
143666
143667
143668
143669
143670
143671
143672
143673
143674
143675
143676
143677
143678
143679
143680

  /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
  ** a virtual term for each vector component. The expression object
  ** used by each such virtual term is pExpr (the full vector IN(...) 
  ** expression). The WhereTerm.iField variable identifies the index within
  ** the vector on the LHS that the virtual term represents.
  **
  ** This only works if the RHS is a simple SELECT (not a compound) that does
  ** not use window functions.
  */
  if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
   && pExpr->pLeft->op==TK_VECTOR
   && pExpr->x.pSelect->pPrior==0
#ifndef SQLITE_OMIT_WINDOWFUNC
   && pExpr->x.pSelect->pWin==0
#endif
  ){
    int i;
    for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
      int idxNew;
      idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
      pWC->a[idxNew].iField = i+1;
      exprAnalyze(pSrc, pWC, idxNew);
142271
142272
142273
142274
142275
142276
142277
142278
142279
142280

142281
142282
142283
142284
142285
142286
142287
  }else if( ExprHasProperty(p, EP_xIsSelect) ){
    if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
    mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
  }else if( p->x.pList ){
    mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
  }
#ifndef SQLITE_OMIT_WINDOWFUNC
  if( p->op==TK_FUNCTION && p->y.pWin ){
    mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition);
    mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy);

  }
#endif
  return mask;
}
SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
  return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0;
}







|


>







143824
143825
143826
143827
143828
143829
143830
143831
143832
143833
143834
143835
143836
143837
143838
143839
143840
143841
  }else if( ExprHasProperty(p, EP_xIsSelect) ){
    if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
    mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
  }else if( p->x.pList ){
    mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
  }
#ifndef SQLITE_OMIT_WINDOWFUNC
  if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && p->y.pWin ){
    mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition);
    mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy);
    mask |= sqlite3WhereExprUsage(pMaskSet, p->y.pWin->pFilter);
  }
#endif
  return mask;
}
SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
  return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0;
}
142480
142481
142482
142483
142484
142485
142486
142487
142488
142489
142490
142491
142492
142493
142494
*/
SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
  return pWInfo->iBreak;
}

/*
** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to
** operate directly on the rowis returned by a WHERE clause.  Return
** ONEPASS_SINGLE (1) if the statement can operation directly because only
** a single row is to be changed.  Return ONEPASS_MULTI (2) if the one-pass
** optimization can be used on multiple 
**
** If the ONEPASS optimization is used (if this routine returns true)
** then also write the indices of open cursors used by ONEPASS
** into aiCur[0] and aiCur[1].  iaCur[0] gets the cursor of the data







|







144034
144035
144036
144037
144038
144039
144040
144041
144042
144043
144044
144045
144046
144047
144048
*/
SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
  return pWInfo->iBreak;
}

/*
** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to
** operate directly on the rowids returned by a WHERE clause.  Return
** ONEPASS_SINGLE (1) if the statement can operation directly because only
** a single row is to be changed.  Return ONEPASS_MULTI (2) if the one-pass
** optimization can be used on multiple 
**
** If the ONEPASS optimization is used (if this routine returns true)
** then also write the indices of open cursors used by ONEPASS
** into aiCur[0] and aiCur[1].  iaCur[0] gets the cursor of the data
142506
142507
142508
142509
142510
142511
142512








142513
142514
142515
142516
142517
142518
142519
    sqlite3DebugPrintf("%s cursors: %d %d\n",
         pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI",
         aiCur[0], aiCur[1]);
  }
#endif
  return pWInfo->eOnePass;
}









/*
** Move the content of pSrc into pDest
*/
static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
  pDest->n = pSrc->n;
  memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));







>
>
>
>
>
>
>
>







144060
144061
144062
144063
144064
144065
144066
144067
144068
144069
144070
144071
144072
144073
144074
144075
144076
144077
144078
144079
144080
144081
    sqlite3DebugPrintf("%s cursors: %d %d\n",
         pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI",
         aiCur[0], aiCur[1]);
  }
#endif
  return pWInfo->eOnePass;
}

/*
** Return TRUE if the WHERE loop uses the OP_DeferredSeek opcode to move
** the data cursor to the row selected by the index cursor.
*/
SQLITE_PRIVATE int sqlite3WhereUsesDeferredSeek(WhereInfo *pWInfo){
  return pWInfo->bDeferredSeek;
}

/*
** Move the content of pSrc into pDest
*/
static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
  pDest->n = pSrc->n;
  memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));
142965
142966
142967
142968
142969
142970
142971
142972
142973
142974
142975
142976
142977
142978
142979
142980
142981
142982
142983
142984
142985
142986
142987
142988
142989
142990
142991
142992
142993
142994
142995
142996
142997
142998
142999
143000
143001
143002
143003
143004
143005
143006
143007
143008
143009
143010
143011
143012
143013
143014
/*
** Two routines for printing the content of an sqlite3_index_info
** structure.  Used for testing and debugging only.  If neither
** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
** are no-ops.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED)
static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
  int i;
  if( !sqlite3WhereTrace ) return;
  for(i=0; i<p->nConstraint; i++){
    sqlite3DebugPrintf("  constraint[%d]: col=%d termid=%d op=%d usabled=%d\n",
       i,
       p->aConstraint[i].iColumn,
       p->aConstraint[i].iTermOffset,
       p->aConstraint[i].op,
       p->aConstraint[i].usable);
  }
  for(i=0; i<p->nOrderBy; i++){
    sqlite3DebugPrintf("  orderby[%d]: col=%d desc=%d\n",
       i,
       p->aOrderBy[i].iColumn,
       p->aOrderBy[i].desc);
  }
}
static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
  int i;
  if( !sqlite3WhereTrace ) return;
  for(i=0; i<p->nConstraint; i++){
    sqlite3DebugPrintf("  usage[%d]: argvIdx=%d omit=%d\n",
       i,
       p->aConstraintUsage[i].argvIndex,
       p->aConstraintUsage[i].omit);
  }
  sqlite3DebugPrintf("  idxNum=%d\n", p->idxNum);
  sqlite3DebugPrintf("  idxStr=%s\n", p->idxStr);
  sqlite3DebugPrintf("  orderByConsumed=%d\n", p->orderByConsumed);
  sqlite3DebugPrintf("  estimatedCost=%g\n", p->estimatedCost);
  sqlite3DebugPrintf("  estimatedRows=%lld\n", p->estimatedRows);
}
#else
#define TRACE_IDX_INPUTS(A)
#define TRACE_IDX_OUTPUTS(A)
#endif

#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Return TRUE if the WHERE clause term pTerm is of a form where it
** could be used with an index to access pSrc, assuming an appropriate
** index existed.







|

















|















|
|







144527
144528
144529
144530
144531
144532
144533
144534
144535
144536
144537
144538
144539
144540
144541
144542
144543
144544
144545
144546
144547
144548
144549
144550
144551
144552
144553
144554
144555
144556
144557
144558
144559
144560
144561
144562
144563
144564
144565
144566
144567
144568
144569
144570
144571
144572
144573
144574
144575
144576
/*
** Two routines for printing the content of an sqlite3_index_info
** structure.  Used for testing and debugging only.  If neither
** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
** are no-ops.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED)
static void whereTraceIndexInfoInputs(sqlite3_index_info *p){
  int i;
  if( !sqlite3WhereTrace ) return;
  for(i=0; i<p->nConstraint; i++){
    sqlite3DebugPrintf("  constraint[%d]: col=%d termid=%d op=%d usabled=%d\n",
       i,
       p->aConstraint[i].iColumn,
       p->aConstraint[i].iTermOffset,
       p->aConstraint[i].op,
       p->aConstraint[i].usable);
  }
  for(i=0; i<p->nOrderBy; i++){
    sqlite3DebugPrintf("  orderby[%d]: col=%d desc=%d\n",
       i,
       p->aOrderBy[i].iColumn,
       p->aOrderBy[i].desc);
  }
}
static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
  int i;
  if( !sqlite3WhereTrace ) return;
  for(i=0; i<p->nConstraint; i++){
    sqlite3DebugPrintf("  usage[%d]: argvIdx=%d omit=%d\n",
       i,
       p->aConstraintUsage[i].argvIndex,
       p->aConstraintUsage[i].omit);
  }
  sqlite3DebugPrintf("  idxNum=%d\n", p->idxNum);
  sqlite3DebugPrintf("  idxStr=%s\n", p->idxStr);
  sqlite3DebugPrintf("  orderByConsumed=%d\n", p->orderByConsumed);
  sqlite3DebugPrintf("  estimatedCost=%g\n", p->estimatedCost);
  sqlite3DebugPrintf("  estimatedRows=%lld\n", p->estimatedRows);
}
#else
#define whereTraceIndexInfoInputs(A)
#define whereTraceIndexInfoOutputs(A)
#endif

#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Return TRUE if the WHERE clause term pTerm is of a form where it
** could be used with an index to access pSrc, assuming an appropriate
** index existed.
143161
143162
143163
143164
143165
143166
143167

143168
143169
143170
143171
143172
143173
143174
143175
      testcase( iCol==BMS-1 );
      testcase( iCol==BMS );
      if( (idxCols & cMask)==0 ){
        Expr *pX = pTerm->pExpr;
        idxCols |= cMask;
        pIdx->aiColumn[n] = pTerm->u.leftColumn;
        pColl = sqlite3ExprCompareCollSeq(pParse, pX);

        pIdx->azColl[n] = ALWAYS(pColl) ? pColl->zName : sqlite3StrBINARY;
        n++;
      }
    }
  }
  assert( (u32)n==pLoop->u.btree.nEq );

  /* Add additional columns needed to make the automatic index into







>
|







144723
144724
144725
144726
144727
144728
144729
144730
144731
144732
144733
144734
144735
144736
144737
144738
      testcase( iCol==BMS-1 );
      testcase( iCol==BMS );
      if( (idxCols & cMask)==0 ){
        Expr *pX = pTerm->pExpr;
        idxCols |= cMask;
        pIdx->aiColumn[n] = pTerm->u.leftColumn;
        pColl = sqlite3ExprCompareCollSeq(pParse, pX);
        assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */
        pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
        n++;
      }
    }
  }
  assert( (u32)n==pLoop->u.btree.nEq );

  /* Add additional columns needed to make the automatic index into
143229
143230
143231
143232
143233
143234
143235
143236
143237

143238
143239
143240
143241
143242
143243
143244
    assert( pLevel->iIdxCur>0 );
    translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
                          pTabItem->regResult, pLevel->iIdxCur);
    sqlite3VdbeGoto(v, addrTop);
    pTabItem->fg.viaCoroutine = 0;
  }else{
    sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
  }
  sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);

  sqlite3VdbeJumpHere(v, addrTop);
  sqlite3ReleaseTempReg(pParse, regRecord);
  
  /* Jump here when skipping the initialization */
  sqlite3VdbeJumpHere(v, addrInit);

end_auto_index_create:







<
|
>







144792
144793
144794
144795
144796
144797
144798

144799
144800
144801
144802
144803
144804
144805
144806
144807
    assert( pLevel->iIdxCur>0 );
    translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
                          pTabItem->regResult, pLevel->iIdxCur);
    sqlite3VdbeGoto(v, addrTop);
    pTabItem->fg.viaCoroutine = 0;
  }else{
    sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);

    sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
  }
  sqlite3VdbeJumpHere(v, addrTop);
  sqlite3ReleaseTempReg(pParse, regRecord);
  
  /* Jump here when skipping the initialization */
  sqlite3VdbeJumpHere(v, addrInit);

end_auto_index_create:
143309
143310
143311
143312
143313
143314
143315
143316
143317
143318
143319
143320
143321
143322
143323
143324
143325
143326
143327
143328
143329
143330
143331
143332
143333
143334
143335
143336
143337
143338
143339
143340
143341
143342
143343
143344
143345




143346
143347
143348
143349
143350
143351
143352
143353
143354
143355
143356
143357
143358
143359
143360
143361
143362
143363
143364
  pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
                           + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
                           + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) );
  if( pIdxInfo==0 ){
    sqlite3ErrorMsg(pParse, "out of memory");
    return 0;
  }

  /* Initialize the structure.  The sqlite3_index_info structure contains
  ** many fields that are declared "const" to prevent xBestIndex from
  ** changing them.  We have to do some funky casting in order to
  ** initialize those fields.
  */
  pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
  pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
  pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
  pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
  *(int*)&pIdxInfo->nConstraint = nTerm;
  *(int*)&pIdxInfo->nOrderBy = nOrderBy;
  *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons;
  *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy;
  *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
                                                                   pUsage;

  pHidden->pWC = pWC;
  pHidden->pParse = pParse;
  for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    u16 op;
    if( pTerm->leftCursor != pSrc->iCursor ) continue;
    if( pTerm->prereqRight & mUnusable ) continue;
    assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
    testcase( pTerm->eOperator & WO_IN );
    testcase( pTerm->eOperator & WO_IS );
    testcase( pTerm->eOperator & WO_ISNULL );
    testcase( pTerm->eOperator & WO_ALL );
    if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
    if( pTerm->wtFlags & TERM_VNULL ) continue;




    if( (pSrc->fg.jointype & JT_LEFT)!=0
     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
     && (pTerm->eOperator & (WO_IS|WO_ISNULL))
    ){
      /* An "IS" term in the WHERE clause where the virtual table is the rhs
      ** of a LEFT JOIN. Do not pass this term to the virtual table
      ** implementation, as this can lead to incorrect results from SQL such
      ** as:
      **
      **   "LEFT JOIN vtab WHERE vtab.col IS NULL"  */
      testcase( pTerm->eOperator & WO_ISNULL );
      testcase( pTerm->eOperator & WO_IS );
      continue;
    }
    assert( pTerm->u.leftColumn>=(-1) );
    pIdxCons[j].iColumn = pTerm->u.leftColumn;
    pIdxCons[j].iTermOffset = i;
    op = pTerm->eOperator & WO_ALL;
    if( op==WO_IN ) op = WO_EQ;







<
<
<
<
<
<




<
|
|
|
|
<
<













>
>
>
>


<

<
<
<
<
<
<
<
<







144872
144873
144874
144875
144876
144877
144878






144879
144880
144881
144882

144883
144884
144885
144886


144887
144888
144889
144890
144891
144892
144893
144894
144895
144896
144897
144898
144899
144900
144901
144902
144903
144904
144905

144906








144907
144908
144909
144910
144911
144912
144913
  pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
                           + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
                           + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) );
  if( pIdxInfo==0 ){
    sqlite3ErrorMsg(pParse, "out of memory");
    return 0;
  }






  pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
  pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
  pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
  pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];

  pIdxInfo->nOrderBy = nOrderBy;
  pIdxInfo->aConstraint = pIdxCons;
  pIdxInfo->aOrderBy = pIdxOrderBy;
  pIdxInfo->aConstraintUsage = pUsage;


  pHidden->pWC = pWC;
  pHidden->pParse = pParse;
  for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    u16 op;
    if( pTerm->leftCursor != pSrc->iCursor ) continue;
    if( pTerm->prereqRight & mUnusable ) continue;
    assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
    testcase( pTerm->eOperator & WO_IN );
    testcase( pTerm->eOperator & WO_IS );
    testcase( pTerm->eOperator & WO_ISNULL );
    testcase( pTerm->eOperator & WO_ALL );
    if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
    if( pTerm->wtFlags & TERM_VNULL ) continue;

    /* tag-20191211-002: WHERE-clause constraints are not useful to the
    ** right-hand table of a LEFT JOIN.  See tag-20191211-001 for the
    ** equivalent restriction for ordinary tables. */
    if( (pSrc->fg.jointype & JT_LEFT)!=0
     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)

    ){








      continue;
    }
    assert( pTerm->u.leftColumn>=(-1) );
    pIdxCons[j].iColumn = pTerm->u.leftColumn;
    pIdxCons[j].iTermOffset = i;
    op = pTerm->eOperator & WO_ALL;
    if( op==WO_IN ) op = WO_EQ;
143381
143382
143383
143384
143385
143386
143387

143388
143389
143390
143391
143392
143393
143394
143395

143396
143397
143398
143399
143400
143401
143402
      assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
      assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
      assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );

      if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
       && sqlite3ExprIsVector(pTerm->pExpr->pRight) 
      ){

        if( i<16 ) mNoOmit |= (1 << i);
        if( op==WO_LT ) pIdxCons[j].op = WO_LE;
        if( op==WO_GT ) pIdxCons[j].op = WO_GE;
      }
    }

    j++;
  }

  for(i=0; i<nOrderBy; i++){
    Expr *pExpr = pOrderBy->a[i].pExpr;
    pIdxOrderBy[i].iColumn = pExpr->iColumn;
    pIdxOrderBy[i].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
  }

  *pmNoOmit = mNoOmit;







>
|







>







144930
144931
144932
144933
144934
144935
144936
144937
144938
144939
144940
144941
144942
144943
144944
144945
144946
144947
144948
144949
144950
144951
144952
144953
      assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
      assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
      assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );

      if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
       && sqlite3ExprIsVector(pTerm->pExpr->pRight) 
      ){
        testcase( j!=i );
        if( j<16 ) mNoOmit |= (1 << j);
        if( op==WO_LT ) pIdxCons[j].op = WO_LE;
        if( op==WO_GT ) pIdxCons[j].op = WO_GE;
      }
    }

    j++;
  }
  pIdxInfo->nConstraint = j;
  for(i=0; i<nOrderBy; i++){
    Expr *pExpr = pOrderBy->a[i].pExpr;
    pIdxOrderBy[i].iColumn = pExpr->iColumn;
    pIdxOrderBy[i].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
  }

  *pmNoOmit = mNoOmit;
143419
143420
143421
143422
143423
143424
143425
143426
143427
143428
143429
143430
143431
143432
143433
143434
143435
** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates
** that this is required.
*/
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
  sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
  int rc;

  TRACE_IDX_INPUTS(p);
  rc = pVtab->pModule->xBestIndex(pVtab, p);
  TRACE_IDX_OUTPUTS(p);

  if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){
    if( rc==SQLITE_NOMEM ){
      sqlite3OomFault(pParse->db);
    }else if( !pVtab->zErrMsg ){
      sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
    }else{







|

|







144970
144971
144972
144973
144974
144975
144976
144977
144978
144979
144980
144981
144982
144983
144984
144985
144986
** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates
** that this is required.
*/
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
  sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
  int rc;

  whereTraceIndexInfoInputs(p);
  rc = pVtab->pModule->xBestIndex(pVtab, p);
  whereTraceIndexInfoOutputs(p);

  if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){
    if( rc==SQLITE_NOMEM ){
      sqlite3OomFault(pParse->db);
    }else if( !pVtab->zErrMsg ){
      sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
    }else{
144102
144103
144104
144105
144106
144107
144108
144109
144110
144111
144112
144113
144114
144115
144116
144117
144118

144119
144120
144121
144122
144123
144124
144125
144126
144127
144128
144129
144130




144131

144132
144133
144134


144135
144136

144137
144138
144139
144140
144141
144142
144143
144144
144145
144146
144147
144148
144149
144150
144151
144152
144153
144154
144155
144156
144157
144158
144159
144160
144161
144162
144163
144164
144165
#endif /* SQLITE_ENABLE_STAT4 */


#ifdef WHERETRACE_ENABLED
/*
** Print the content of a WhereTerm object
*/
static void whereTermPrint(WhereTerm *pTerm, int iTerm){
  if( pTerm==0 ){
    sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
  }else{
    char zType[4];
    char zLeft[50];
    memcpy(zType, "...", 4);
    if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
    if( pTerm->eOperator & WO_EQUIV  ) zType[1] = 'E';
    if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';

    if( pTerm->eOperator & WO_SINGLE ){
      sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
                       pTerm->leftCursor, pTerm->u.leftColumn);
    }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
      sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", 
                       pTerm->u.pOrInfo->indexable);
    }else{
      sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor);
    }
    sqlite3DebugPrintf(
       "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x",
       iTerm, pTerm, zType, zLeft, pTerm->truthProb,




       pTerm->eOperator, pTerm->wtFlags);

    if( pTerm->iField ){
      sqlite3DebugPrintf(" iField=%d\n", pTerm->iField);
    }else{


      sqlite3DebugPrintf("\n");
    }

    sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
  }
}
#endif

#ifdef WHERETRACE_ENABLED
/*
** Show the complete content of a WhereClause
*/
SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
  int i;
  for(i=0; i<pWC->nTerm; i++){
    whereTermPrint(&pWC->a[i], i);
  }
}
#endif

#ifdef WHERETRACE_ENABLED
/*
** Print a WhereLoop object for debugging purposes
*/
static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
  WhereInfo *pWInfo = pWC->pWInfo;
  int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
  struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
  Table *pTab = pItem->pTab;
  Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
  sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
                     p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);







|



|

|



>










|
|
>
>
>
>
|
>

|
<
>
>
|

>












|








|







145653
145654
145655
145656
145657
145658
145659
145660
145661
145662
145663
145664
145665
145666
145667
145668
145669
145670
145671
145672
145673
145674
145675
145676
145677
145678
145679
145680
145681
145682
145683
145684
145685
145686
145687
145688
145689
145690

145691
145692
145693
145694
145695
145696
145697
145698
145699
145700
145701
145702
145703
145704
145705
145706
145707
145708
145709
145710
145711
145712
145713
145714
145715
145716
145717
145718
145719
145720
145721
145722
145723
145724
#endif /* SQLITE_ENABLE_STAT4 */


#ifdef WHERETRACE_ENABLED
/*
** Print the content of a WhereTerm object
*/
SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
  if( pTerm==0 ){
    sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
  }else{
    char zType[8];
    char zLeft[50];
    memcpy(zType, "....", 5);
    if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
    if( pTerm->eOperator & WO_EQUIV  ) zType[1] = 'E';
    if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
    if( pTerm->wtFlags & TERM_CODED  ) zType[3] = 'C';
    if( pTerm->eOperator & WO_SINGLE ){
      sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
                       pTerm->leftCursor, pTerm->u.leftColumn);
    }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
      sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", 
                       pTerm->u.pOrInfo->indexable);
    }else{
      sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor);
    }
    sqlite3DebugPrintf(
       "TERM-%-3d %p %s %-12s op=%03x wtFlags=%04x",
       iTerm, pTerm, zType, zLeft, pTerm->eOperator, pTerm->wtFlags);
    /* The 0x10000 .wheretrace flag causes extra information to be
    ** shown about each Term */
    if( sqlite3WhereTrace & 0x10000 ){
      sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx",
        pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight);
    }
    if( pTerm->iField ){
      sqlite3DebugPrintf(" iField=%d", pTerm->iField);

    }
    if( pTerm->iParent>=0 ){
      sqlite3DebugPrintf(" iParent=%d", pTerm->iParent);
    }
    sqlite3DebugPrintf("\n");
    sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
  }
}
#endif

#ifdef WHERETRACE_ENABLED
/*
** Show the complete content of a WhereClause
*/
SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
  int i;
  for(i=0; i<pWC->nTerm; i++){
    sqlite3WhereTermPrint(&pWC->a[i], i);
  }
}
#endif

#ifdef WHERETRACE_ENABLED
/*
** Print a WhereLoop object for debugging purposes
*/
SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
  WhereInfo *pWInfo = pWC->pWInfo;
  int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
  struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
  Table *pTab = pItem->pTab;
  Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
  sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
                     p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
144176
144177
144178
144179
144180
144181
144182
144183
144184
144185
144186
144187
144188
144189
144190
144191
144192
144193
144194
144195
144196
144197
144198
144199
144200
144201
144202
144203
144204
144205
144206
144207
      sqlite3DebugPrintf(".%-16s %2d", zName, p->u.btree.nEq);
    }else{
      sqlite3DebugPrintf("%20s","");
    }
  }else{
    char *z;
    if( p->u.vtab.idxStr ){
      z = sqlite3_mprintf("(%d,\"%s\",%x)",
                p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask);
    }else{
      z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask);
    }
    sqlite3DebugPrintf(" %-19s", z);
    sqlite3_free(z);
  }
  if( p->wsFlags & WHERE_SKIPSCAN ){
    sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
  }else{
    sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
  }
  sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
  if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){
    int i;
    for(i=0; i<p->nLTerm; i++){
      whereTermPrint(p->aLTerm[i], i);
    }
  }
}
#endif

/*
** Convert bulk memory into a valid WhereLoop that can be passed







|
















|







145735
145736
145737
145738
145739
145740
145741
145742
145743
145744
145745
145746
145747
145748
145749
145750
145751
145752
145753
145754
145755
145756
145757
145758
145759
145760
145761
145762
145763
145764
145765
145766
      sqlite3DebugPrintf(".%-16s %2d", zName, p->u.btree.nEq);
    }else{
      sqlite3DebugPrintf("%20s","");
    }
  }else{
    char *z;
    if( p->u.vtab.idxStr ){
      z = sqlite3_mprintf("(%d,\"%s\",%#x)",
                p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask);
    }else{
      z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask);
    }
    sqlite3DebugPrintf(" %-19s", z);
    sqlite3_free(z);
  }
  if( p->wsFlags & WHERE_SKIPSCAN ){
    sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
  }else{
    sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
  }
  sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
  if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){
    int i;
    for(i=0; i<p->nLTerm; i++){
      sqlite3WhereTermPrint(p->aLTerm[i], i);
    }
  }
}
#endif

/*
** Convert bulk memory into a valid WhereLoop that can be passed
144297
144298
144299
144300
144301
144302
144303

144304
144305
144306
144307
144308
144309
144310
  }
  sqlite3WhereClauseClear(&pWInfo->sWC);
  while( pWInfo->pLoops ){
    WhereLoop *p = pWInfo->pLoops;
    pWInfo->pLoops = p->pNextLoop;
    whereLoopDelete(db, p);
  }

  sqlite3DbFreeNN(db, pWInfo);
}

/*
** Return TRUE if all of the following are true:
**
**   (1)  X has the same or lower cost that Y







>







145856
145857
145858
145859
145860
145861
145862
145863
145864
145865
145866
145867
145868
145869
145870
  }
  sqlite3WhereClauseClear(&pWInfo->sWC);
  while( pWInfo->pLoops ){
    WhereLoop *p = pWInfo->pLoops;
    pWInfo->pLoops = p->pNextLoop;
    whereLoopDelete(db, p);
  }
  assert( pWInfo->pExprMods==0 );
  sqlite3DbFreeNN(db, pWInfo);
}

/*
** Return TRUE if all of the following are true:
**
**   (1)  X has the same or lower cost that Y
144497
144498
144499
144500
144501
144502
144503


144504
144505
144506
144507
144508
144509
144510
144511
144512
144513
144514
144515
144516
144517
144518
144519
144520
144521
144522
144523
144524
144525
144526
144527
144528
144529
144530
144531
144532
144533
144534
144535
144536
144537
144538
144539
144540
144541
144542
144543
144544
144545
144546
144547
144548
144549
144550
144551
144552
144553
144554
144555
144556
144557
144558
144559
144560
144561
144562
144563
144564
144565
  /* Stop the search once we hit the query planner search limit */
  if( pBuilder->iPlanLimit==0 ){
    WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n"));
    if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0;
    return SQLITE_DONE;
  }
  pBuilder->iPlanLimit--;



  /* If pBuilder->pOrSet is defined, then only keep track of the costs
  ** and prereqs.
  */
  if( pBuilder->pOrSet!=0 ){
    if( pTemplate->nLTerm ){
#if WHERETRACE_ENABLED
      u16 n = pBuilder->pOrSet->n;
      int x =
#endif
      whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
                                    pTemplate->nOut);
#if WHERETRACE_ENABLED /* 0x8 */
      if( sqlite3WhereTrace & 0x8 ){
        sqlite3DebugPrintf(x?"   or-%d:  ":"   or-X:  ", n);
        whereLoopPrint(pTemplate, pBuilder->pWC);
      }
#endif
    }
    return SQLITE_OK;
  }

  /* Look for an existing WhereLoop to replace with pTemplate
  */
  whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
  ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);

  if( ppPrev==0 ){
    /* There already exists a WhereLoop on the list that is better
    ** than pTemplate, so just ignore pTemplate */
#if WHERETRACE_ENABLED /* 0x8 */
    if( sqlite3WhereTrace & 0x8 ){
      sqlite3DebugPrintf("   skip: ");
      whereLoopPrint(pTemplate, pBuilder->pWC);
    }
#endif
    return SQLITE_OK;  
  }else{
    p = *ppPrev;
  }

  /* If we reach this point it means that either p[] should be overwritten
  ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
  ** WhereLoop and insert it.
  */
#if WHERETRACE_ENABLED /* 0x8 */
  if( sqlite3WhereTrace & 0x8 ){
    if( p!=0 ){
      sqlite3DebugPrintf("replace: ");
      whereLoopPrint(p, pBuilder->pWC);
      sqlite3DebugPrintf("   with: ");
    }else{
      sqlite3DebugPrintf("    add: ");
    }
    whereLoopPrint(pTemplate, pBuilder->pWC);
  }
#endif
  if( p==0 ){
    /* Allocate a new WhereLoop to add to the end of the list */
    *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop));
    if( p==0 ) return SQLITE_NOMEM_BKPT;
    whereLoopInit(p);







>
>















|








<








|















|




|







146057
146058
146059
146060
146061
146062
146063
146064
146065
146066
146067
146068
146069
146070
146071
146072
146073
146074
146075
146076
146077
146078
146079
146080
146081
146082
146083
146084
146085
146086
146087
146088
146089

146090
146091
146092
146093
146094
146095
146096
146097
146098
146099
146100
146101
146102
146103
146104
146105
146106
146107
146108
146109
146110
146111
146112
146113
146114
146115
146116
146117
146118
146119
146120
146121
146122
146123
146124
146125
146126
  /* Stop the search once we hit the query planner search limit */
  if( pBuilder->iPlanLimit==0 ){
    WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n"));
    if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0;
    return SQLITE_DONE;
  }
  pBuilder->iPlanLimit--;

  whereLoopAdjustCost(pWInfo->pLoops, pTemplate);

  /* If pBuilder->pOrSet is defined, then only keep track of the costs
  ** and prereqs.
  */
  if( pBuilder->pOrSet!=0 ){
    if( pTemplate->nLTerm ){
#if WHERETRACE_ENABLED
      u16 n = pBuilder->pOrSet->n;
      int x =
#endif
      whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
                                    pTemplate->nOut);
#if WHERETRACE_ENABLED /* 0x8 */
      if( sqlite3WhereTrace & 0x8 ){
        sqlite3DebugPrintf(x?"   or-%d:  ":"   or-X:  ", n);
        sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
      }
#endif
    }
    return SQLITE_OK;
  }

  /* Look for an existing WhereLoop to replace with pTemplate
  */

  ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);

  if( ppPrev==0 ){
    /* There already exists a WhereLoop on the list that is better
    ** than pTemplate, so just ignore pTemplate */
#if WHERETRACE_ENABLED /* 0x8 */
    if( sqlite3WhereTrace & 0x8 ){
      sqlite3DebugPrintf("   skip: ");
      sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
    }
#endif
    return SQLITE_OK;  
  }else{
    p = *ppPrev;
  }

  /* If we reach this point it means that either p[] should be overwritten
  ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
  ** WhereLoop and insert it.
  */
#if WHERETRACE_ENABLED /* 0x8 */
  if( sqlite3WhereTrace & 0x8 ){
    if( p!=0 ){
      sqlite3DebugPrintf("replace: ");
      sqlite3WhereLoopPrint(p, pBuilder->pWC);
      sqlite3DebugPrintf("   with: ");
    }else{
      sqlite3DebugPrintf("    add: ");
    }
    sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
  }
#endif
  if( p==0 ){
    /* Allocate a new WhereLoop to add to the end of the list */
    *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop));
    if( p==0 ) return SQLITE_NOMEM_BKPT;
    whereLoopInit(p);
144575
144576
144577
144578
144579
144580
144581
144582
144583
144584
144585
144586
144587
144588
144589
      if( ppTail==0 ) break;
      pToDel = *ppTail;
      if( pToDel==0 ) break;
      *ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
      if( sqlite3WhereTrace & 0x8 ){
        sqlite3DebugPrintf(" delete: ");
        whereLoopPrint(pToDel, pBuilder->pWC);
      }
#endif
      whereLoopDelete(db, pToDel);
    }
  }
  rc = whereLoopXfer(db, p, pTemplate);
  if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){







|







146136
146137
146138
146139
146140
146141
146142
146143
146144
146145
146146
146147
146148
146149
146150
      if( ppTail==0 ) break;
      pToDel = *ppTail;
      if( pToDel==0 ) break;
      *ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
      if( sqlite3WhereTrace & 0x8 ){
        sqlite3DebugPrintf(" delete: ");
        sqlite3WhereLoopPrint(pToDel, pBuilder->pWC);
      }
#endif
      whereLoopDelete(db, pToDel);
    }
  }
  rc = whereLoopXfer(db, p, pTemplate);
  if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
144651
144652
144653
144654
144655
144656
144657
144658


144659
144660
144661
144662
144663
144664
144665
144666
144667



144668
144669
144670
144671
144672
144673
144674
        /* If a truth probability is specified using the likelihood() hints,
        ** then use the probability provided by the application. */
        pLoop->nOut += pTerm->truthProb;
      }else{
        /* In the absence of explicit truth probabilities, use heuristics to
        ** guess a reasonable truth probability. */
        pLoop->nOut--;
        if( pTerm->eOperator&(WO_EQ|WO_IS) ){


          Expr *pRight = pTerm->pExpr->pRight;
          int k = 0;
          testcase( pTerm->pExpr->op==TK_IS );
          if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
            k = 10;
          }else{
            k = 20;
          }
          if( iReduce<k ) iReduce = k;



        }
      }
    }
  }
  if( pLoop->nOut > nRow-iReduce )  pLoop->nOut = nRow - iReduce;
}








|
>
>








|
>
>
>







146212
146213
146214
146215
146216
146217
146218
146219
146220
146221
146222
146223
146224
146225
146226
146227
146228
146229
146230
146231
146232
146233
146234
146235
146236
146237
146238
146239
146240
        /* If a truth probability is specified using the likelihood() hints,
        ** then use the probability provided by the application. */
        pLoop->nOut += pTerm->truthProb;
      }else{
        /* In the absence of explicit truth probabilities, use heuristics to
        ** guess a reasonable truth probability. */
        pLoop->nOut--;
        if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0
         && (pTerm->wtFlags & TERM_HIGHTRUTH)==0  /* tag-20200224-1 */
        ){
          Expr *pRight = pTerm->pExpr->pRight;
          int k = 0;
          testcase( pTerm->pExpr->op==TK_IS );
          if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
            k = 10;
          }else{
            k = 20;
          }
          if( iReduce<k ){
            pTerm->wtFlags |= TERM_HEURTRUTH;
            iReduce = k;
          }
        }
      }
    }
  }
  if( pLoop->nOut > nRow-iReduce )  pLoop->nOut = nRow - iReduce;
}

144784
144785
144786
144787
144788
144789
144790
144791
144792

144793
144794
144795
144796
144797
144798
144799
  int rc = SQLITE_OK;             /* Return code */
  LogEst rSize;                   /* Number of rows in the table */
  LogEst rLogSize;                /* Logarithm of table size */
  WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */

  pNew = pBuilder->pNew;
  if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
  WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d\n",
                     pProbe->pTable->zName,pProbe->zName, pNew->u.btree.nEq));


  assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
  assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
  if( pNew->wsFlags & WHERE_BTM_LIMIT ){
    opMask = WO_LT|WO_LE;
  }else{
    assert( pNew->u.btree.nBtm==0 );







|
|
>







146350
146351
146352
146353
146354
146355
146356
146357
146358
146359
146360
146361
146362
146363
146364
146365
146366
  int rc = SQLITE_OK;             /* Return code */
  LogEst rSize;                   /* Number of rows in the table */
  LogEst rLogSize;                /* Logarithm of table size */
  WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */

  pNew = pBuilder->pNew;
  if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
  WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d\n",
                     pProbe->pTable->zName,pProbe->zName,
                     pNew->u.btree.nEq, pNew->nSkip));

  assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
  assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
  if( pNew->wsFlags & WHERE_BTM_LIMIT ){
    opMask = WO_LT|WO_LE;
  }else{
    assert( pNew->u.btree.nBtm==0 );
144831
144832
144833
144834
144835
144836
144837
144838
144839
144840
144841
144842
144843
144844
144845
144846
144847
144848
144849
144850
144851
144852
144853
144854
144855
144856
144857
    }
    if( pTerm->prereqRight & pNew->maskSelf ) continue;

    /* Do not allow the upper bound of a LIKE optimization range constraint
    ** to mix with a lower range bound from some other source */
    if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;

    /* Do not allow constraints from the WHERE clause to be used by the
    ** right table of a LEFT JOIN.  Only constraints in the ON clause are
    ** allowed */
    if( (pSrc->fg.jointype & JT_LEFT)!=0
     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ){
      continue;
    }

    if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
      pBuilder->bldFlags |= SQLITE_BLDF_UNIQUE;
    }else{
      pBuilder->bldFlags |= SQLITE_BLDF_INDEXED;
    }
    pNew->wsFlags = saved_wsFlags;
    pNew->u.btree.nEq = saved_nEq;
    pNew->u.btree.nBtm = saved_nBtm;
    pNew->u.btree.nTop = saved_nTop;
    pNew->nLTerm = saved_nLTerm;
    if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */







|
|
|







|

|







146398
146399
146400
146401
146402
146403
146404
146405
146406
146407
146408
146409
146410
146411
146412
146413
146414
146415
146416
146417
146418
146419
146420
146421
146422
146423
146424
    }
    if( pTerm->prereqRight & pNew->maskSelf ) continue;

    /* Do not allow the upper bound of a LIKE optimization range constraint
    ** to mix with a lower range bound from some other source */
    if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;

    /* tag-20191211-001:  Do not allow constraints from the WHERE clause to
    ** be used by the right table of a LEFT JOIN.  Only constraints in the
    ** ON clause are allowed.  See tag-20191211-002 for the vtab equivalent. */
    if( (pSrc->fg.jointype & JT_LEFT)!=0
     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ){
      continue;
    }

    if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
      pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
    }else{
      pBuilder->bldFlags1 |= SQLITE_BLDF1_INDEXED;
    }
    pNew->wsFlags = saved_wsFlags;
    pNew->u.btree.nEq = saved_nEq;
    pNew->u.btree.nBtm = saved_nBtm;
    pNew->u.btree.nTop = saved_nTop;
    pNew->nLTerm = saved_nLTerm;
    if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
145008
145009
145010
145011
145012
145013
145014





















145015
145016
145017
145018
145019
145020
145021
          }else{
            rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
          }
          if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
          if( rc!=SQLITE_OK ) break;          /* Jump out of the pTerm loop */
          if( nOut ){
            pNew->nOut = sqlite3LogEst(nOut);





















            if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
            pNew->nOut -= nIn;
          }
        }
        if( nOut==0 )
#endif
        {







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







146575
146576
146577
146578
146579
146580
146581
146582
146583
146584
146585
146586
146587
146588
146589
146590
146591
146592
146593
146594
146595
146596
146597
146598
146599
146600
146601
146602
146603
146604
146605
146606
146607
146608
146609
          }else{
            rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
          }
          if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
          if( rc!=SQLITE_OK ) break;          /* Jump out of the pTerm loop */
          if( nOut ){
            pNew->nOut = sqlite3LogEst(nOut);
            if( nEq==1
             /* TUNING: Mark terms as "low selectivity" if they seem likely
             ** to be true for half or more of the rows in the table.
             ** See tag-202002240-1 */
             && pNew->nOut+10 > pProbe->aiRowLogEst[0]
            ){
#if WHERETRACE_ENABLED /* 0x01 */
              if( sqlite3WhereTrace & 0x01 ){
                sqlite3DebugPrintf(
                   "STAT4 determines term has low selectivity:\n");
                sqlite3WhereTermPrint(pTerm, 999);
              }
#endif
              pTerm->wtFlags |= TERM_HIGHTRUTH;
              if( pTerm->wtFlags & TERM_HEURTRUTH ){
                /* If the term has previously been used with an assumption of
                ** higher selectivity, then set the flag to rerun the
                ** loop computations. */
                pBuilder->bldFlags2 |= SQLITE_BLDF2_2NDPASS;
              }
            }
            if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
            pNew->nOut -= nIn;
          }
        }
        if( nOut==0 )
#endif
        {
145082
145083
145084
145085
145086
145087
145088

145089

145090
145091
145092
145093
145094
145095
145096
  ** contains fewer than 2^17 rows we assume otherwise in other parts of
  ** the code). And, even if it is not, it should not be too much slower. 
  ** On the other hand, the extra seeks could end up being significantly
  ** more expensive.  */
  assert( 42==sqlite3LogEst(18) );
  if( saved_nEq==saved_nSkip
   && saved_nEq+1<pProbe->nKeyCol

   && pProbe->noSkipScan==0

   && OptimizationEnabled(db, SQLITE_SkipScan)
   && pProbe->aiRowLogEst[saved_nEq+1]>=42  /* TUNING: Minimum for skip-scan */
   && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
  ){
    LogEst nIter;
    pNew->u.btree.nEq++;
    pNew->nSkip++;







>

>







146670
146671
146672
146673
146674
146675
146676
146677
146678
146679
146680
146681
146682
146683
146684
146685
146686
  ** contains fewer than 2^17 rows we assume otherwise in other parts of
  ** the code). And, even if it is not, it should not be too much slower. 
  ** On the other hand, the extra seeks could end up being significantly
  ** more expensive.  */
  assert( 42==sqlite3LogEst(18) );
  if( saved_nEq==saved_nSkip
   && saved_nEq+1<pProbe->nKeyCol
   && saved_nEq==pNew->nLTerm
   && pProbe->noSkipScan==0
   && pProbe->hasStat1!=0
   && OptimizationEnabled(db, SQLITE_SkipScan)
   && pProbe->aiRowLogEst[saved_nEq+1]>=42  /* TUNING: Minimum for skip-scan */
   && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
  ){
    LogEst nIter;
    pNew->u.btree.nEq++;
    pNew->nSkip++;
145150
145151
145152
145153
145154
145155
145156
145157





145158
145159
145160
145161
145162
145163
145164
145165
145166
145167
145168
145169

145170
145171
145172
145173
145174
145175
145176
  }
  return 0;
}

/* Check to see if a partial index with pPartIndexWhere can be used
** in the current query.  Return true if it can be and false if not.
*/
static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){





  int i;
  WhereTerm *pTerm;
  Parse *pParse = pWC->pWInfo->pParse;
  while( pWhere->op==TK_AND ){
    if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0;
    pWhere = pWhere->pRight;
  }
  if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
  for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    Expr *pExpr;
    pExpr = pTerm->pExpr;
    if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)

     && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) 
    ){
      return 1;
    }
  }
  return 0;
}







|
>
>
>
>
>




|







>







146740
146741
146742
146743
146744
146745
146746
146747
146748
146749
146750
146751
146752
146753
146754
146755
146756
146757
146758
146759
146760
146761
146762
146763
146764
146765
146766
146767
146768
146769
146770
146771
146772
  }
  return 0;
}

/* Check to see if a partial index with pPartIndexWhere can be used
** in the current query.  Return true if it can be and false if not.
*/
static int whereUsablePartialIndex(
  int iTab,             /* The table for which we want an index */
  int isLeft,           /* True if iTab is the right table of a LEFT JOIN */
  WhereClause *pWC,     /* The WHERE clause of the query */
  Expr *pWhere          /* The WHERE clause from the partial index */
){
  int i;
  WhereTerm *pTerm;
  Parse *pParse = pWC->pWInfo->pParse;
  while( pWhere->op==TK_AND ){
    if( !whereUsablePartialIndex(iTab,isLeft,pWC,pWhere->pLeft) ) return 0;
    pWhere = pWhere->pRight;
  }
  if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
  for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    Expr *pExpr;
    pExpr = pTerm->pExpr;
    if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
     && (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin))
     && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) 
    ){
      return 1;
    }
  }
  return 0;
}
145325
145326
145327
145328
145329
145330
145331

145332
145333


145334
145335
145336
145337
145338
145339
145340
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */

  /* Loop over all indices. If there was an INDEXED BY clause, then only 
  ** consider index pProbe.  */
  for(; rc==SQLITE_OK && pProbe; 
      pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
  ){

    if( pProbe->pPartIdxWhere!=0
     && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){


      testcase( pNew->iTab!=pSrc->iCursor );  /* See ticket [98d973b8f5] */
      continue;  /* Partial index inappropriate for this query */
    }
    if( pProbe->bNoQuery ) continue;
    rSize = pProbe->aiRowLogEst[0];
    pNew->u.btree.nEq = 0;
    pNew->u.btree.nBtm = 0;







>

|
>
>







146921
146922
146923
146924
146925
146926
146927
146928
146929
146930
146931
146932
146933
146934
146935
146936
146937
146938
146939
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */

  /* Loop over all indices. If there was an INDEXED BY clause, then only 
  ** consider index pProbe.  */
  for(; rc==SQLITE_OK && pProbe; 
      pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
  ){
    int isLeft = (pSrc->fg.jointype & JT_OUTER)!=0;
    if( pProbe->pPartIdxWhere!=0
     && !whereUsablePartialIndex(pSrc->iCursor, isLeft, pWC,
                                 pProbe->pPartIdxWhere)
    ){
      testcase( pNew->iTab!=pSrc->iCursor );  /* See ticket [98d973b8f5] */
      continue;  /* Partial index inappropriate for this query */
    }
    if( pProbe->bNoQuery ) continue;
    rSize = pProbe->aiRowLogEst[0];
    pNew->u.btree.nEq = 0;
    pNew->u.btree.nBtm = 0;
145421
145422
145423
145424
145425
145426
145427
145428
145429
145430
145431
145432
145433
145434
145435
145436
145437
        whereLoopOutputAdjust(pWC, pNew, rSize);
        rc = whereLoopInsert(pBuilder, pNew);
        pNew->nOut = rSize;
        if( rc ) break;
      }
    }

    pBuilder->bldFlags = 0;
    rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
    if( pBuilder->bldFlags==SQLITE_BLDF_INDEXED ){
      /* If a non-unique index is used, or if a prefix of the key for
      ** unique index is used (making the index functionally non-unique)
      ** then the sqlite_stat1 data becomes important for scoring the
      ** plan */
      pTab->tabFlags |= TF_StatsUsed;
    }
#ifdef SQLITE_ENABLE_STAT4







|

|







147020
147021
147022
147023
147024
147025
147026
147027
147028
147029
147030
147031
147032
147033
147034
147035
147036
        whereLoopOutputAdjust(pWC, pNew, rSize);
        rc = whereLoopInsert(pBuilder, pNew);
        pNew->nOut = rSize;
        if( rc ) break;
      }
    }

    pBuilder->bldFlags1 = 0;
    rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
    if( pBuilder->bldFlags1==SQLITE_BLDF1_INDEXED ){
      /* If a non-unique index is used, or if a prefix of the key for
      ** unique index is used (making the index functionally non-unique)
      ** then the sqlite_stat1 data becomes important for scoring the
      ** plan */
      pTab->tabFlags |= TF_StatsUsed;
    }
#ifdef SQLITE_ENABLE_STAT4
145553
145554
145555
145556
145557
145558
145559



145560




145561
145562
145563
145564
145565
145566
145567
145568
145569
145570
145571
145572
145573
145574
145575
145576
145577
145578
145579
145580
      pTerm = &pWC->a[j];
      pNew->prereq |= pTerm->prereqRight;
      assert( iTerm<pNew->nLSlot );
      pNew->aLTerm[iTerm] = pTerm;
      if( iTerm>mxTerm ) mxTerm = iTerm;
      testcase( iTerm==15 );
      testcase( iTerm==16 );



      if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;




      if( (pTerm->eOperator & WO_IN)!=0 ){
        /* A virtual table that is constrained by an IN clause may not
        ** consume the ORDER BY clause because (1) the order of IN terms
        ** is not necessarily related to the order of output terms and
        ** (2) Multiple outputs from a single IN value will not merge
        ** together.  */
        pIdxInfo->orderByConsumed = 0;
        pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
        *pbIn = 1; assert( (mExclude & WO_IN)==0 );
      }
    }
  }
  pNew->u.vtab.omitMask &= ~mNoOmit;

  pNew->nLTerm = mxTerm+1;
  for(i=0; i<=mxTerm; i++){
    if( pNew->aLTerm[i]==0 ){
      /* The non-zero argvIdx values must be contiguous.  Raise an
      ** error if they are not */
      sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);







>
>
>
|
>
>
>
>












<







147152
147153
147154
147155
147156
147157
147158
147159
147160
147161
147162
147163
147164
147165
147166
147167
147168
147169
147170
147171
147172
147173
147174
147175
147176
147177
147178

147179
147180
147181
147182
147183
147184
147185
      pTerm = &pWC->a[j];
      pNew->prereq |= pTerm->prereqRight;
      assert( iTerm<pNew->nLSlot );
      pNew->aLTerm[iTerm] = pTerm;
      if( iTerm>mxTerm ) mxTerm = iTerm;
      testcase( iTerm==15 );
      testcase( iTerm==16 );
      if( pUsage[i].omit ){
        if( i<16 && ((1<<i)&mNoOmit)==0 ){
          testcase( i!=iTerm );
          pNew->u.vtab.omitMask |= 1<<iTerm;
        }else{
          testcase( i!=iTerm );
        }
      }
      if( (pTerm->eOperator & WO_IN)!=0 ){
        /* A virtual table that is constrained by an IN clause may not
        ** consume the ORDER BY clause because (1) the order of IN terms
        ** is not necessarily related to the order of output terms and
        ** (2) Multiple outputs from a single IN value will not merge
        ** together.  */
        pIdxInfo->orderByConsumed = 0;
        pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
        *pbIn = 1; assert( (mExclude & WO_IN)==0 );
      }
    }
  }


  pNew->nLTerm = mxTerm+1;
  for(i=0; i<=mxTerm; i++){
    if( pNew->aLTerm[i]==0 ){
      /* The non-zero argvIdx values must be contiguous.  Raise an
      ** error if they are not */
      sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
145848
145849
145850
145851
145852
145853
145854
145855

145856
145857
145858
145859
145860
145861
145862
#endif
        {
          rc = whereLoopAddBtree(&sSubBuild, mPrereq);
        }
        if( rc==SQLITE_OK ){
          rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
        }
        assert( rc==SQLITE_OK || sCur.n==0 );

        if( sCur.n==0 ){
          sSum.n = 0;
          break;
        }else if( once ){
          whereOrMove(&sSum, &sCur);
          once = 0;
        }else{







|
>







147453
147454
147455
147456
147457
147458
147459
147460
147461
147462
147463
147464
147465
147466
147467
147468
#endif
        {
          rc = whereLoopAddBtree(&sSubBuild, mPrereq);
        }
        if( rc==SQLITE_OK ){
          rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
        }
        assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0 );
        testcase( rc==SQLITE_DONE );
        if( sCur.n==0 ){
          sSum.n = 0;
          break;
        }else if( once ){
          whereOrMove(&sSum, &sCur);
          once = 0;
        }else{
146087
146088
146089
146090
146091
146092
146093
146094
146095



146096
146097
146098
146099
146100
146101
146102
        ** optimization, and then only if they are actually used
        ** by the query plan */
        assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
        for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
        if( j>=pLoop->nLTerm ) continue;
      }
      if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
        if( sqlite3ExprCollSeqMatch(pWInfo->pParse, 
                  pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){



          continue;
        }
        testcase( pTerm->pExpr->op==TK_IS );
      }
      obSat |= MASKBIT(i);
    }








|
|
>
>
>







147693
147694
147695
147696
147697
147698
147699
147700
147701
147702
147703
147704
147705
147706
147707
147708
147709
147710
147711
        ** optimization, and then only if they are actually used
        ** by the query plan */
        assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
        for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
        if( j>=pLoop->nLTerm ) continue;
      }
      if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
        Parse *pParse = pWInfo->pParse;
        CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[i].pExpr);
        CollSeq *pColl2 = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr);
        assert( pColl1 );
        if( pColl2==0 || sqlite3StrICmp(pColl1->zName, pColl2->zName) ){
          continue;
        }
        testcase( pTerm->pExpr->op==TK_IS );
      }
      obSat |= MASKBIT(i);
    }

146868
146869
146870
146871
146872
146873
146874






















146875
146876
146877
146878
146879
146880
146881
  w.eCode = 1;
  w.xExprCallback = exprNodeIsDeterministic;
  w.xSelectCallback = sqlite3SelectWalkFail;
  sqlite3WalkExpr(&w, p);
  return w.eCode;
}























/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop.  Later, the calling routine
** should invoke sqlite3WhereEnd() with the return value of this function
** in order to complete the WHERE clause processing.
**







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







148477
148478
148479
148480
148481
148482
148483
148484
148485
148486
148487
148488
148489
148490
148491
148492
148493
148494
148495
148496
148497
148498
148499
148500
148501
148502
148503
148504
148505
148506
148507
148508
148509
148510
148511
148512
  w.eCode = 1;
  w.xExprCallback = exprNodeIsDeterministic;
  w.xSelectCallback = sqlite3SelectWalkFail;
  sqlite3WalkExpr(&w, p);
  return w.eCode;
}

  
#ifdef WHERETRACE_ENABLED
/*
** Display all WhereLoops in pWInfo
*/
static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
  if( sqlite3WhereTrace ){    /* Display all of the WhereLoop objects */
    WhereLoop *p;
    int i;
    static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
                                           "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
    for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
      p->cId = zLabel[i%(sizeof(zLabel)-1)];
      sqlite3WhereLoopPrint(p, pWC);
    }
  }
}
# define WHERETRACE_ALL_LOOPS(W,C) showAllWhereLoops(W,C)
#else
# define WHERETRACE_ALL_LOOPS(W,C)
#endif

/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop.  Later, the calling routine
** should invoke sqlite3WhereEnd() with the return value of this function
** in order to complete the WHERE clause processing.
**
147161
147162
147163
147164
147165
147166
147167

147168
147169
147170
147171
147172
147173
147174
147175








147176
147177



147178
147179
147180
147181
147182
147183
147184
147185


147186
147187

147188
147189
147190
147191
147192
147193
147194
      sSelect.pWhere = pWhere;
      sSelect.pOrderBy = pOrderBy;
      sSelect.pEList = pResultSet;
      sqlite3TreeViewSelect(0, &sSelect, 0);
    }
  }
  if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */

    sqlite3WhereClausePrint(sWLB.pWC);
  }
#endif

  if( nTabList!=1 || whereShortCut(&sWLB)==0 ){
    rc = whereLoopAddAll(&sWLB);
    if( rc ) goto whereBeginError;
  








#ifdef WHERETRACE_ENABLED
    if( sqlite3WhereTrace ){    /* Display all of the WhereLoop objects */



      WhereLoop *p;
      int i;
      static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
                                             "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
      for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
        p->cId = zLabel[i%(sizeof(zLabel)-1)];
        whereLoopPrint(p, sWLB.pWC);
      }


    }
#endif

  
    wherePathSolver(pWInfo, 0);
    if( db->mallocFailed ) goto whereBeginError;
    if( pWInfo->pOrderBy ){
       wherePathSolver(pWInfo, pWInfo->nRowOut+1);
       if( db->mallocFailed ) goto whereBeginError;
    }







>







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

>
>


>







148792
148793
148794
148795
148796
148797
148798
148799
148800
148801
148802
148803
148804
148805
148806
148807
148808
148809
148810
148811
148812
148813
148814
148815
148816

148817
148818
148819
148820



148821

148822
148823
148824
148825
148826
148827
148828
148829
148830
148831
148832
148833
148834
148835
      sSelect.pWhere = pWhere;
      sSelect.pOrderBy = pOrderBy;
      sSelect.pEList = pResultSet;
      sqlite3TreeViewSelect(0, &sSelect, 0);
    }
  }
  if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
    sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
    sqlite3WhereClausePrint(sWLB.pWC);
  }
#endif

  if( nTabList!=1 || whereShortCut(&sWLB)==0 ){
    rc = whereLoopAddAll(&sWLB);
    if( rc ) goto whereBeginError;

#ifdef SQLITE_ENABLE_STAT4
    /* If one or more WhereTerm.truthProb values were used in estimating
    ** loop parameters, but then those truthProb values were subsequently
    ** changed based on STAT4 information while computing subsequent loops,
    ** then we need to rerun the whole loop building process so that all
    ** loops will be built using the revised truthProb values. */
    if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){
      WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC);
      WHERETRACE(0xffff, 

           ("**** Redo all loop computations due to"
            " TERM_HIGHTRUTH changes ****\n"));
      while( pWInfo->pLoops ){
        WhereLoop *p = pWInfo->pLoops;



        pWInfo->pLoops = p->pNextLoop;

        whereLoopDelete(db, p);
      }
      rc = whereLoopAddAll(&sWLB);
      if( rc ) goto whereBeginError;
    }
#endif
    WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC);
  
    wherePathSolver(pWInfo, 0);
    if( db->mallocFailed ) goto whereBeginError;
    if( pWInfo->pOrderBy ){
       wherePathSolver(pWInfo, pWInfo->nRowOut+1);
       if( db->mallocFailed ) goto whereBeginError;
    }
147217
147218
147219
147220
147221
147222
147223
147224
147225
147226
147227
147228
147229
147230
147231
      case WHERE_DISTINCT_UNORDERED: {
        sqlite3DebugPrintf("  DISTINCT=unordered");
        break;
      }
    }
    sqlite3DebugPrintf("\n");
    for(ii=0; ii<pWInfo->nLevel; ii++){
      whereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC);
    }
  }
#endif

  /* Attempt to omit tables from the join that do not affect the result.
  ** For a table to not affect the result, the following must be true:
  **







|







148858
148859
148860
148861
148862
148863
148864
148865
148866
148867
148868
148869
148870
148871
148872
      case WHERE_DISTINCT_UNORDERED: {
        sqlite3DebugPrintf("  DISTINCT=unordered");
        break;
      }
    }
    sqlite3DebugPrintf("\n");
    for(ii=0; ii<pWInfo->nLevel; ii++){
      sqlite3WhereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC);
    }
  }
#endif

  /* Attempt to omit tables from the join that do not affect the result.
  ** For a table to not affect the result, the following must be true:
  **
147242
147243
147244
147245
147246
147247
147248
147249
147250
147251
147252
147253
147254
147255
147256
147257
147258
147259
147260
147261
147262
147263
  **     CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
  **     CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
  **     CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
  **
  ** then table t2 can be omitted from the following:
  **
  **     SELECT v1, v3 FROM t1 
  **       LEFT JOIN t2 USING (t1.ipk=t2.ipk)
  **       LEFT JOIN t3 USING (t1.ipk=t3.ipk)
  **
  ** or from:
  **
  **     SELECT DISTINCT v1, v3 FROM t1 
  **       LEFT JOIN t2
  **       LEFT JOIN t3 USING (t1.ipk=t3.ipk)
  */
  notReady = ~(Bitmask)0;
  if( pWInfo->nLevel>=2
   && pResultSet!=0               /* guarantees condition (1) above */
   && OptimizationEnabled(db, SQLITE_OmitNoopJoin)
  ){
    int i;







|
|





|







148883
148884
148885
148886
148887
148888
148889
148890
148891
148892
148893
148894
148895
148896
148897
148898
148899
148900
148901
148902
148903
148904
  **     CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
  **     CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
  **     CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
  **
  ** then table t2 can be omitted from the following:
  **
  **     SELECT v1, v3 FROM t1 
  **       LEFT JOIN t2 ON (t1.ipk=t2.ipk)
  **       LEFT JOIN t3 ON (t1.ipk=t3.ipk)
  **
  ** or from:
  **
  **     SELECT DISTINCT v1, v3 FROM t1 
  **       LEFT JOIN t2
  **       LEFT JOIN t3 ON (t1.ipk=t3.ipk)
  */
  notReady = ~(Bitmask)0;
  if( pWInfo->nLevel>=2
   && pResultSet!=0               /* guarantees condition (1) above */
   && OptimizationEnabled(db, SQLITE_OmitNoopJoin)
  ){
    int i;
147299
147300
147301
147302
147303
147304
147305





147306

147307
147308
147309
147310
147311
147312
147313
        int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
        memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
      }
      pWInfo->nLevel--;
      nTabList--;
    }
  }





  WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));

  pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;

  /* If the caller is an UPDATE or DELETE statement that is requesting
  ** to use a one-pass algorithm, determine if this is appropriate.
  **
  ** A one-pass approach can be used if the caller has requested one
  ** and either (a) the scan visits at most one row or (b) each







>
>
>
>
>

>







148940
148941
148942
148943
148944
148945
148946
148947
148948
148949
148950
148951
148952
148953
148954
148955
148956
148957
148958
148959
148960
        int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
        memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
      }
      pWInfo->nLevel--;
      nTabList--;
    }
  }
#if defined(WHERETRACE_ENABLED)
  if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
    sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n");
    sqlite3WhereClausePrint(sWLB.pWC);
  }
  WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
#endif
  pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;

  /* If the caller is an UPDATE or DELETE statement that is requesting
  ** to use a one-pass algorithm, determine if this is appropriate.
  **
  ** A one-pass approach can be used if the caller has requested one
  ** and either (a) the scan visits at most one row or (b) each
147445
147446
147447
147448
147449
147450
147451
147452
147453
147454
147455
147456
147457
147458
147459
        sqlite3VdbeSetP4KeyInfo(pParse, pIx);
        if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
         && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
         && (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0
         && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
         && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
        ){
          sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
        }
        VdbeComment((v, "%s", pIx->zName));
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
        {
          u64 colUsed = 0;
          int ii, jj;
          for(ii=0; ii<pIx->nColumn; ii++){







|







149092
149093
149094
149095
149096
149097
149098
149099
149100
149101
149102
149103
149104
149105
149106
        sqlite3VdbeSetP4KeyInfo(pParse, pIx);
        if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
         && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
         && (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0
         && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
         && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
        ){
          sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ);
        }
        VdbeComment((v, "%s", pIx->zName));
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
        {
          u64 colUsed = 0;
          int ii, jj;
          for(ii=0; ii<pIx->nColumn; ii++){
147603
147604
147605
147606
147607
147608
147609
















147610
147611
147612
147613

147614
147615
147616
147617
147618
147619
147620
      int j;
      sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
      for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
        sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
        if( pIn->eEndLoopOp!=OP_Noop ){
          if( pIn->nPrefix ){
            assert( pLoop->wsFlags & WHERE_IN_EARLYOUT );
















            sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur,
                              sqlite3VdbeCurrentAddr(v)+2,
                              pIn->iBase, pIn->nPrefix);
            VdbeCoverage(v);

          }
          sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
          VdbeCoverage(v);
          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Prev);
          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Next);
        }
        sqlite3VdbeJumpHere(v, pIn->addrInTop-1);







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







149250
149251
149252
149253
149254
149255
149256
149257
149258
149259
149260
149261
149262
149263
149264
149265
149266
149267
149268
149269
149270
149271
149272
149273
149274
149275
149276
149277
149278
149279
149280
149281
149282
149283
149284
      int j;
      sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
      for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
        sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
        if( pIn->eEndLoopOp!=OP_Noop ){
          if( pIn->nPrefix ){
            assert( pLoop->wsFlags & WHERE_IN_EARLYOUT );
            if( pLevel->iLeftJoin ){
              /* For LEFT JOIN queries, cursor pIn->iCur may not have been
              ** opened yet. This occurs for WHERE clauses such as
              ** "a = ? AND b IN (...)", where the index is on (a, b). If
              ** the RHS of the (a=?) is NULL, then the "b IN (...)" may
              ** never have been coded, but the body of the loop run to
              ** return the null-row. So, if the cursor is not open yet,
              ** jump over the OP_Next or OP_Prev instruction about to
              ** be coded.  */
              sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur, 
                  sqlite3VdbeCurrentAddr(v) + 2 + 
                     ((pLoop->wsFlags & WHERE_VIRTUALTABLE)==0)
              );
              VdbeCoverage(v);
            }
            if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){
              sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur,
                  sqlite3VdbeCurrentAddr(v)+2,
                  pIn->iBase, pIn->nPrefix);
              VdbeCoverage(v);
            }
          }
          sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
          VdbeCoverage(v);
          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Prev);
          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Next);
        }
        sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
147770
147771
147772
147773
147774
147775
147776








147777
147778
147779
147780
147781
147782
147783
        }
      }
#ifdef SQLITE_DEBUG
      if( db->flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n");
#endif
    }
  }









  /* Final cleanup
  */
  pParse->nQueryLoop = pWInfo->savedNQueryLoop;
  whereInfoFree(db, pWInfo);
  return;
}







>
>
>
>
>
>
>
>







149434
149435
149436
149437
149438
149439
149440
149441
149442
149443
149444
149445
149446
149447
149448
149449
149450
149451
149452
149453
149454
149455
        }
      }
#ifdef SQLITE_DEBUG
      if( db->flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n");
#endif
    }
  }

  /* Undo all Expr node modifications */
  while( pWInfo->pExprMods ){
    WhereExprMod *p = pWInfo->pExprMods;
    pWInfo->pExprMods = p->pNext;
    memcpy(p->pExpr, &p->orig, sizeof(p->orig));
    sqlite3DbFree(db, p);
  }

  /* Final cleanup
  */
  pParse->nQueryLoop = pWInfo->savedNQueryLoop;
  whereInfoFree(db, pWInfo);
  return;
}
148569
148570
148571
148572
148573
148574
148575











148576

148577

148578
148579
148580
148581
148582
148583
148584
148585
148586
148587
148588
148589
148590
148591
148592
148593
148594
148595
148596
148597
          }
        }
      }
      /* Fall through.  */

    case TK_AGG_FUNCTION:
    case TK_COLUMN: {











      Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0);

      p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);

      if( p->pSub ){
        assert( ExprHasProperty(pExpr, EP_Static)==0 );
        ExprSetProperty(pExpr, EP_Static);
        sqlite3ExprDelete(pParse->db, pExpr);
        ExprClearProperty(pExpr, EP_Static);
        memset(pExpr, 0, sizeof(Expr));

        pExpr->op = TK_COLUMN;
        pExpr->iColumn = p->pSub->nExpr-1;
        pExpr->iTable = p->pWin->iEphCsr;
        pExpr->y.pTab = p->pTab;
      }

      break;
    }

    default: /* no-op */
      break;
  }








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








|



|







150241
150242
150243
150244
150245
150246
150247
150248
150249
150250
150251
150252
150253
150254
150255
150256
150257
150258
150259
150260
150261
150262
150263
150264
150265
150266
150267
150268
150269
150270
150271
150272
150273
150274
150275
150276
150277
150278
150279
150280
150281
150282
          }
        }
      }
      /* Fall through.  */

    case TK_AGG_FUNCTION:
    case TK_COLUMN: {
      int iCol = -1;
      if( p->pSub ){
        int i;
        for(i=0; i<p->pSub->nExpr; i++){
          if( 0==sqlite3ExprCompare(0, p->pSub->a[i].pExpr, pExpr, -1) ){
            iCol = i;
            break;
          }
        }
      }
      if( iCol<0 ){
        Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0);
        if( pDup && pDup->op==TK_AGG_FUNCTION ) pDup->op = TK_FUNCTION;
        p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
      }
      if( p->pSub ){
        assert( ExprHasProperty(pExpr, EP_Static)==0 );
        ExprSetProperty(pExpr, EP_Static);
        sqlite3ExprDelete(pParse->db, pExpr);
        ExprClearProperty(pExpr, EP_Static);
        memset(pExpr, 0, sizeof(Expr));

        pExpr->op = TK_COLUMN;
        pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol);
        pExpr->iTable = p->pWin->iEphCsr;
        pExpr->y.pTab = p->pTab;
      }
      if( pParse->db->mallocFailed ) return WRC_Abort;
      break;
    }

    default: /* no-op */
      break;
  }

148664
148665
148666
148667
148668
148669
148670

148671

148672
148673
148674

148675
148676
148677
148678
148679
148680
148681
  ExprList *pAppend,      /* List of values to append. Might be NULL */
  int bIntToNull
){
  if( pAppend ){
    int i;
    int nInit = pList ? pList->nExpr : 0;
    for(i=0; i<pAppend->nExpr; i++){

      Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);

      if( bIntToNull && pDup && pDup->op==TK_INTEGER ){
        pDup->op = TK_NULL;
        pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);

      }
      pList = sqlite3ExprListAppend(pParse, pList, pDup);
      if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
    }
  }
  return pList;
}







>

>
|


>







150349
150350
150351
150352
150353
150354
150355
150356
150357
150358
150359
150360
150361
150362
150363
150364
150365
150366
150367
150368
150369
  ExprList *pAppend,      /* List of values to append. Might be NULL */
  int bIntToNull
){
  if( pAppend ){
    int i;
    int nInit = pList ? pList->nExpr : 0;
    for(i=0; i<pAppend->nExpr; i++){
      int iDummy;
      Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
      assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
      if( bIntToNull && pDup && sqlite3ExprIsInteger(pDup, &iDummy) ){
        pDup->op = TK_NULL;
        pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
        pDup->u.zToken = 0;
      }
      pList = sqlite3ExprListAppend(pParse, pList, pDup);
      if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
    }
  }
  return pList;
}
148699
148700
148701
148702
148703
148704
148705

148706
148707
148708
148709
148710
148711
148712
148713
148714
148715
148716
148717
148718
148719
148720
148721
148722
148723
148724
148725
148726
148727
148728
148729
    Expr *pHaving = p->pHaving;
    ExprList *pSort = 0;

    ExprList *pSublist = 0;       /* Expression list for sub-query */
    Window *pMWin = p->pWin;      /* Master window object */
    Window *pWin;                 /* Window object iterator */
    Table *pTab;


    pTab = sqlite3DbMallocZero(db, sizeof(Table));
    if( pTab==0 ){
      return SQLITE_NOMEM;
    }

    p->pSrc = 0;
    p->pWhere = 0;
    p->pGroupBy = 0;
    p->pHaving = 0;
    p->selFlags &= ~SF_Aggregate;
    p->selFlags |= SF_WinRewrite;

    /* Create the ORDER BY clause for the sub-select. This is the concatenation
    ** of the window PARTITION and ORDER BY clauses. Then, if this makes it
    ** redundant, remove the ORDER BY from the parent SELECT.  */
    pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0);
    pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1);
    if( pSort && p->pOrderBy && p->pOrderBy->nExpr<=pSort->nExpr ){
      int nSave = pSort->nExpr;
      pSort->nExpr = p->pOrderBy->nExpr;
      if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){
        sqlite3ExprListDelete(db, p->pOrderBy);
        p->pOrderBy = 0;







>



|












|







150387
150388
150389
150390
150391
150392
150393
150394
150395
150396
150397
150398
150399
150400
150401
150402
150403
150404
150405
150406
150407
150408
150409
150410
150411
150412
150413
150414
150415
150416
150417
150418
    Expr *pHaving = p->pHaving;
    ExprList *pSort = 0;

    ExprList *pSublist = 0;       /* Expression list for sub-query */
    Window *pMWin = p->pWin;      /* Master window object */
    Window *pWin;                 /* Window object iterator */
    Table *pTab;
    u32 selFlags = p->selFlags;

    pTab = sqlite3DbMallocZero(db, sizeof(Table));
    if( pTab==0 ){
      return sqlite3ErrorToParser(db, SQLITE_NOMEM);
    }

    p->pSrc = 0;
    p->pWhere = 0;
    p->pGroupBy = 0;
    p->pHaving = 0;
    p->selFlags &= ~SF_Aggregate;
    p->selFlags |= SF_WinRewrite;

    /* Create the ORDER BY clause for the sub-select. This is the concatenation
    ** of the window PARTITION and ORDER BY clauses. Then, if this makes it
    ** redundant, remove the ORDER BY from the parent SELECT.  */
    pSort = exprListAppendList(pParse, 0, pMWin->pPartition, 1);
    pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1);
    if( pSort && p->pOrderBy && p->pOrderBy->nExpr<=pSort->nExpr ){
      int nSave = pSort->nExpr;
      pSort->nExpr = p->pOrderBy->nExpr;
      if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){
        sqlite3ExprListDelete(db, p->pOrderBy);
        p->pOrderBy = 0;
148788
148789
148790
148791
148792
148793
148794

148795



148796
148797
148798
148799
148800
148801
148802
148803
148804
148805
148806
148807
148808
148809
148810
148811
148812
148813







148814
148815
148816
148817
148818
148819
148820
    p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
    if( p->pSrc ){
      Table *pTab2;
      p->pSrc->a[0].pSelect = pSub;
      sqlite3SrcListAssignCursors(pParse, p->pSrc);
      pSub->selFlags |= SF_Expanded;
      pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);

      if( pTab2==0 ){



        rc = SQLITE_NOMEM;
      }else{
        memcpy(pTab, pTab2, sizeof(Table));
        pTab->tabFlags |= TF_Ephemeral;
        p->pSrc->a[0].pTab = pTab;
        pTab = pTab2;
      }
      sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr);
      sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
      sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
      sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);
    }else{
      sqlite3SelectDelete(db, pSub);
    }
    if( db->mallocFailed ) rc = SQLITE_NOMEM;
    sqlite3DbFree(db, pTab);
  }








  return rc;
}

/*
** Unlink the Window object from the Select to which it is attached,
** if it is attached.
*/







>

>
>
>







<
<
<
<







>
>
>
>
>
>
>







150477
150478
150479
150480
150481
150482
150483
150484
150485
150486
150487
150488
150489
150490
150491
150492
150493
150494
150495




150496
150497
150498
150499
150500
150501
150502
150503
150504
150505
150506
150507
150508
150509
150510
150511
150512
150513
150514
150515
150516
    p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
    if( p->pSrc ){
      Table *pTab2;
      p->pSrc->a[0].pSelect = pSub;
      sqlite3SrcListAssignCursors(pParse, p->pSrc);
      pSub->selFlags |= SF_Expanded;
      pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
      pSub->selFlags |= (selFlags & SF_Aggregate);
      if( pTab2==0 ){
        /* Might actually be some other kind of error, but in that case
        ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get
        ** the correct error message regardless. */
        rc = SQLITE_NOMEM;
      }else{
        memcpy(pTab, pTab2, sizeof(Table));
        pTab->tabFlags |= TF_Ephemeral;
        p->pSrc->a[0].pTab = pTab;
        pTab = pTab2;
      }




    }else{
      sqlite3SelectDelete(db, pSub);
    }
    if( db->mallocFailed ) rc = SQLITE_NOMEM;
    sqlite3DbFree(db, pTab);
  }

  if( rc ){
    if( pParse->nErr==0 ){
      assert( pParse->db->mallocFailed );
      sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
    }
    sqlite3SelectReset(pParse, p);
  }
  return rc;
}

/*
** Unlink the Window object from the Select to which it is attached,
** if it is attached.
*/
149039
149040
149041
149042
149043
149044
149045
149046

149047
149048
149049


149050
149051
149052
149053
149054
149055
149056


149057


149058
149059


149060
149061
149062
149063
149064
149065
149066
149067
149068
149069
149070


149071
149072
149073





149074
149075
149076
149077
149078
149079
149080
    }
    pSel->pWin = pWin;
    pWin->ppThis = &pSel->pWin;
  }
}

/*
** Return 0 if the two window objects are identical, or non-zero otherwise.

** Identical window objects can be processed in a single scan.
*/
SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){


  if( p1->eFrmType!=p2->eFrmType ) return 1;
  if( p1->eStart!=p2->eStart ) return 1;
  if( p1->eEnd!=p2->eEnd ) return 1;
  if( p1->eExclude!=p2->eExclude ) return 1;
  if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
  if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
  if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1;


  if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1;


  if( bFilter ){
    if( sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1) ) return 1;


  }
  return 0;
}


/*
** This is called by code in select.c before it calls sqlite3WhereBegin()
** to begin iterating through the sub-query results. It is used to allocate
** and initialize registers and cursors used by sqlite3WindowCodeStep().
*/
SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){


  Window *pWin;
  Vdbe *v = sqlite3GetVdbe(pParse);






  /* Allocate registers to use for PARTITION BY values, if any. Initialize
  ** said registers to NULL.  */
  if( pMWin->pPartition ){
    int nExpr = pMWin->pPartition->nExpr;
    pMWin->regPart = pParse->nMem+1;
    pParse->nMem += nExpr;
    sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nExpr-1);







|
>
|


>
>






|
>
>
|
>
>

|
>
>










|
>
>



>
>
>
>
>







150735
150736
150737
150738
150739
150740
150741
150742
150743
150744
150745
150746
150747
150748
150749
150750
150751
150752
150753
150754
150755
150756
150757
150758
150759
150760
150761
150762
150763
150764
150765
150766
150767
150768
150769
150770
150771
150772
150773
150774
150775
150776
150777
150778
150779
150780
150781
150782
150783
150784
150785
150786
150787
150788
150789
150790
150791
150792
    }
    pSel->pWin = pWin;
    pWin->ppThis = &pSel->pWin;
  }
}

/*
** Return 0 if the two window objects are identical, 1 if they are
** different, or 2 if it cannot be determined if the objects are identical
** or not. Identical window objects can be processed in a single scan.
*/
SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){
  int res;
  if( NEVER(p1==0) || NEVER(p2==0) ) return 1;
  if( p1->eFrmType!=p2->eFrmType ) return 1;
  if( p1->eStart!=p2->eStart ) return 1;
  if( p1->eEnd!=p2->eEnd ) return 1;
  if( p1->eExclude!=p2->eExclude ) return 1;
  if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
  if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
  if( (res = sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1)) ){
    return res;
  }
  if( (res = sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1)) ){
    return res;
  }
  if( bFilter ){
    if( (res = sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1)) ){
      return res;
    }
  }
  return 0;
}


/*
** This is called by code in select.c before it calls sqlite3WhereBegin()
** to begin iterating through the sub-query results. It is used to allocate
** and initialize registers and cursors used by sqlite3WindowCodeStep().
*/
SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
  int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr;
  Window *pMWin = pSelect->pWin;
  Window *pWin;
  Vdbe *v = sqlite3GetVdbe(pParse);

  sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
  sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
  sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
  sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);

  /* Allocate registers to use for PARTITION BY values, if any. Initialize
  ** said registers to NULL.  */
  if( pMWin->pPartition ){
    int nExpr = pMWin->pPartition->nExpr;
    pMWin->regPart = pParse->nMem+1;
    pParse->nMem += nExpr;
    sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nExpr-1);
149332
149333
149334
149335
149336
149337
149338
149339
149340
149341
149342
149343
149344
149345
149346
    int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
    int i;

    assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );

    /* All OVER clauses in the same window function aggregate step must
    ** be the same. */
    assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)==0 );

    for(i=0; i<nArg; i++){
      if( i!=1 || pFunc->zName!=nth_valueName ){
        sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);
      }else{
        sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i);
      }







|







151044
151045
151046
151047
151048
151049
151050
151051
151052
151053
151054
151055
151056
151057
151058
    int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
    int i;

    assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );

    /* All OVER clauses in the same window function aggregate step must
    ** be the same. */
    assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)!=1 );

    for(i=0; i<nArg; i++){
      if( i!=1 || pFunc->zName!=nth_valueName ){
        sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);
      }else{
        sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i);
      }
149654
149655
149656
149657
149658
149659
149660

149661
149662
149663
149664
149665
149666
149667
static int windowInitAccum(Parse *pParse, Window *pMWin){
  Vdbe *v = sqlite3GetVdbe(pParse);
  int regArg;
  int nArg = 0;
  Window *pWin;
  for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
    FuncDef *pFunc = pWin->pFunc;

    sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
    nArg = MAX(nArg, windowArgCount(pWin));
    if( pMWin->regStartRowid==0 ){
      if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){
        sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp);
        sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
      }







>







151366
151367
151368
151369
151370
151371
151372
151373
151374
151375
151376
151377
151378
151379
151380
static int windowInitAccum(Parse *pParse, Window *pMWin){
  Vdbe *v = sqlite3GetVdbe(pParse);
  int regArg;
  int nArg = 0;
  Window *pWin;
  for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
    FuncDef *pFunc = pWin->pFunc;
    assert( pWin->regAccum );
    sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
    nArg = MAX(nArg, windowArgCount(pWin));
    if( pMWin->regStartRowid==0 ){
      if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){
        sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp);
        sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
      }
150032
150033
150034
150035
150036
150037
150038




150039
150040
150041
150042
150043
150044
150045
      pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0);
      pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0);
      pNew->eFrmType = p->eFrmType;
      pNew->eEnd = p->eEnd;
      pNew->eStart = p->eStart;
      pNew->eExclude = p->eExclude;
      pNew->regResult = p->regResult;




      pNew->pStart = sqlite3ExprDup(db, p->pStart, 0);
      pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0);
      pNew->pOwner = pOwner;
      pNew->bImplicitFrame = p->bImplicitFrame;
    }
  }
  return pNew;







>
>
>
>







151745
151746
151747
151748
151749
151750
151751
151752
151753
151754
151755
151756
151757
151758
151759
151760
151761
151762
      pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0);
      pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0);
      pNew->eFrmType = p->eFrmType;
      pNew->eEnd = p->eEnd;
      pNew->eStart = p->eStart;
      pNew->eExclude = p->eExclude;
      pNew->regResult = p->regResult;
      pNew->regAccum = p->regAccum;
      pNew->iArgCol = p->iArgCol;
      pNew->iEphCsr = p->iEphCsr;
      pNew->bExprArgs = p->bExprArgs;
      pNew->pStart = sqlite3ExprDup(db, p->pStart, 0);
      pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0);
      pNew->pOwner = pOwner;
      pNew->bImplicitFrame = p->bImplicitFrame;
    }
  }
  return pNew;
150869
150870
150871
150872
150873
150874
150875

150876
150877
150878
150879
150880
150881
150882
  static Expr *tokenExpr(Parse *pParse, int op, Token t){
    Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
    if( p ){
      /* memset(p, 0, sizeof(Expr)); */
      p->op = (u8)op;
      p->affExpr = 0;
      p->flags = EP_Leaf;

      p->iAgg = -1;
      p->pLeft = p->pRight = 0;
      p->x.pList = 0;
      p->pAggInfo = 0;
      p->y.pTab = 0;
      p->op2 = 0;
      p->iTable = 0;







>







152586
152587
152588
152589
152590
152591
152592
152593
152594
152595
152596
152597
152598
152599
152600
  static Expr *tokenExpr(Parse *pParse, int op, Token t){
    Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
    if( p ){
      /* memset(p, 0, sizeof(Expr)); */
      p->op = (u8)op;
      p->affExpr = 0;
      p->flags = EP_Leaf;
      ExprClearVVAProperties(p);
      p->iAgg = -1;
      p->pLeft = p->pRight = 0;
      p->x.pList = 0;
      p->pAggInfo = 0;
      p->y.pTab = 0;
      p->op2 = 0;
      p->iTable = 0;
151031
151032
151033
151034
151035
151036
151037
151038
151039

151040
151041
151042
151043
151044
151045
151046
151047
151048
151049
151050
151051
151052
151053
151054
151055
#define sqlite3ParserARG_STORE
#define sqlite3ParserCTX_SDECL Parse *pParse;
#define sqlite3ParserCTX_PDECL ,Parse *pParse
#define sqlite3ParserCTX_PARAM ,pParse
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
#define YYNSTATE             550
#define YYNRULE              385

#define YYNTOKEN             181
#define YY_MAX_SHIFT         549
#define YY_MIN_SHIFTREDUCE   800
#define YY_MAX_SHIFTREDUCE   1184
#define YY_ERROR_ACTION      1185
#define YY_ACCEPT_ACTION     1186
#define YY_NO_ACTION         1187
#define YY_MIN_REDUCE        1188
#define YY_MAX_REDUCE        1572
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))

/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
** Applications can choose to define yytestcase() in the %include section







|

>

|
|
|
|
|
|
|
|







152749
152750
152751
152752
152753
152754
152755
152756
152757
152758
152759
152760
152761
152762
152763
152764
152765
152766
152767
152768
152769
152770
152771
152772
152773
152774
#define sqlite3ParserARG_STORE
#define sqlite3ParserCTX_SDECL Parse *pParse;
#define sqlite3ParserCTX_PDECL ,Parse *pParse
#define sqlite3ParserCTX_PARAM ,pParse
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
#define YYNSTATE             551
#define YYNRULE              385
#define YYNRULE_WITH_ACTION  325
#define YYNTOKEN             181
#define YY_MAX_SHIFT         550
#define YY_MIN_SHIFTREDUCE   801
#define YY_MAX_SHIFTREDUCE   1185
#define YY_ERROR_ACTION      1186
#define YY_ACCEPT_ACTION     1187
#define YY_NO_ACTION         1188
#define YY_MIN_REDUCE        1189
#define YY_MAX_REDUCE        1573
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))

/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
** Applications can choose to define yytestcase() in the %include section
151110
151111
151112
151113
151114
151115
151116
151117
151118
151119
151120
151121
151122
151123
151124
151125
151126
151127
151128
151129
151130
151131
151132
151133
151134
151135
151136
151137
151138
151139
151140
151141
151142
151143
151144
151145
151146
151147
151148
151149
151150
151151
151152
151153
151154
151155
151156
151157
151158
151159
151160
151161
151162
151163
151164
151165
151166
151167
151168
151169
151170
151171
151172
151173
151174
151175
151176
151177
151178
151179
151180
151181
151182
151183
151184
151185
151186
151187
151188
151189
151190
151191
151192
151193
151194
151195
151196
151197
151198
151199
151200
151201
151202
151203
151204
151205
151206
151207
151208
151209
151210
151211
151212
151213
151214
151215
151216
151217
151218
151219
151220
151221
151222
151223
151224
151225
151226
151227
151228
151229
151230
151231
151232
151233
151234
151235
151236
151237
151238
151239
151240
151241
151242
151243
151244
151245
151246
151247
151248
151249
151250
151251
151252
151253
151254
151255
151256
151257
151258
151259
151260
151261
151262
151263
151264
151265
151266
151267
151268
151269
151270
151271
151272
151273
151274
151275
151276
151277
151278
151279
151280
151281
151282
151283
151284
151285
151286
151287
151288
151289
151290
151291
151292
151293
151294
151295
151296
151297
151298
151299
151300
151301
151302
151303
151304
151305
151306
151307
151308
151309
151310
151311
151312
151313
151314
151315
151316
151317
151318
151319
**  yy_reduce_ofst[]   For each state, the offset into yy_action for
**                     shifting non-terminals after a reduce.
**  yy_default[]       Default action for each state.
**
*********** Begin parsing tables **********************************************/
#define YY_ACTTAB_COUNT (1958)
static const YYACTIONTYPE yy_action[] = {
 /*     0 */   544, 1219,  544,  449, 1257,  544, 1236,  544,  114,  111,
 /*    10 */   211,  544, 1534,  544, 1257,  521,  114,  111,  211,  390,
 /*    20 */  1229,  342,   42,   42,   42,   42, 1222,   42,   42,   71,
 /*    30 */    71,  934, 1221,   71,   71,   71,   71, 1459, 1490,  935,
 /*    40 */   817,  451,    6,  121,  122,  112, 1162, 1162, 1003, 1006,
 /*    50 */   996,  996,  119,  119,  120,  120,  120,  120, 1540,  390,
 /*    60 */  1355, 1514,  549,    2, 1190,  194,  526,  434,  143,  291,
 /*    70 */   526,  136,  526,  369,  261,  502,  272,  383, 1270,  525,
 /*    80 */   501,  491,  164,  121,  122,  112, 1162, 1162, 1003, 1006,
 /*    90 */   996,  996,  119,  119,  120,  120,  120,  120, 1355,  440,
 /*   100 */  1511,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   110 */   115,  422,  266,  266,  266,  266, 1495,  356, 1497,  433,
 /*   120 */   355, 1495,  515,  522, 1482,  541, 1111,  541, 1111,  390,
 /*   130 */   403,  241,  208,  114,  111,  211,   98,  290,  535,  221,
 /*   140 */  1026,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   150 */   115,  422, 1139,  121,  122,  112, 1162, 1162, 1003, 1006,
 /*   160 */   996,  996,  119,  119,  120,  120,  120,  120,  404,  426,
 /*   170 */   117,  117,  116,  116,  116,  115,  422, 1415,  466,  123,
 /*   180 */   118,  118,  118,  118,  117,  117,  116,  116,  116,  115,
 /*   190 */   422,  116,  116,  116,  115,  422,  538,  538,  538,  390,
 /*   200 */   503,  120,  120,  120,  120,  113, 1048, 1139, 1140, 1141,
 /*   210 */  1048,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   220 */   115,  422, 1458,  121,  122,  112, 1162, 1162, 1003, 1006,
 /*   230 */   996,  996,  119,  119,  120,  120,  120,  120,  390,  442,
 /*   240 */   314,   83,  461,   81,  357,  380, 1139,   80,  118,  118,
 /*   250 */   118,  118,  117,  117,  116,  116,  116,  115,  422,  179,
 /*   260 */   432,  422,  121,  122,  112, 1162, 1162, 1003, 1006,  996,
 /*   270 */   996,  119,  119,  120,  120,  120,  120,  432,  431,  266,
 /*   280 */   266,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   290 */   115,  422,  541, 1106,  900,  504, 1139,  114,  111,  211,
 /*   300 */  1428, 1139, 1140, 1141,  206,  489, 1106,  390,  447, 1106,
 /*   310 */   543,  328,  120,  120,  120,  120,  298, 1428, 1430,   17,
 /*   320 */   118,  118,  118,  118,  117,  117,  116,  116,  116,  115,
 /*   330 */   422,  121,  122,  112, 1162, 1162, 1003, 1006,  996,  996,
 /*   340 */   119,  119,  120,  120,  120,  120,  390, 1355,  432, 1139,
 /*   350 */   480, 1139, 1140, 1141,  993,  993, 1004, 1007,  443,  118,
 /*   360 */   118,  118,  118,  117,  117,  116,  116,  116,  115,  422,
 /*   370 */   121,  122,  112, 1162, 1162, 1003, 1006,  996,  996,  119,
 /*   380 */   119,  120,  120,  120,  120, 1051, 1051,  463, 1428,  118,
 /*   390 */   118,  118,  118,  117,  117,  116,  116,  116,  115,  422,
 /*   400 */  1139,  449,  544, 1423, 1139, 1140, 1141,  233,  963, 1139,
 /*   410 */   479,  476,  475,  171,  358,  390,  164,  405,  412,  839,
 /*   420 */   474,  164,  185,  332,   71,   71, 1240,  997,  118,  118,
 /*   430 */   118,  118,  117,  117,  116,  116,  116,  115,  422,  121,
 /*   440 */   122,  112, 1162, 1162, 1003, 1006,  996,  996,  119,  119,
 /*   450 */   120,  120,  120,  120,  390, 1139, 1140, 1141,  832,   12,
 /*   460 */   313,  507,  163,  354, 1139, 1140, 1141,  114,  111,  211,
 /*   470 */   506,  290,  535,  544,  276,  180,  290,  535,  121,  122,
 /*   480 */   112, 1162, 1162, 1003, 1006,  996,  996,  119,  119,  120,
 /*   490 */   120,  120,  120,  343,  482,   71,   71,  118,  118,  118,
 /*   500 */   118,  117,  117,  116,  116,  116,  115,  422, 1139,  209,
 /*   510 */   409,  521, 1139, 1106, 1568,  376,  252,  269,  340,  485,
 /*   520 */   335,  484,  238,  390,  511,  362, 1106, 1124,  331, 1106,
 /*   530 */   191,  407,  286,   32,  455,  441,  118,  118,  118,  118,
 /*   540 */   117,  117,  116,  116,  116,  115,  422,  121,  122,  112,
 /*   550 */  1162, 1162, 1003, 1006,  996,  996,  119,  119,  120,  120,
 /*   560 */   120,  120,  390, 1139, 1140, 1141,  984, 1139, 1140, 1141,
 /*   570 */  1139,  233,  490, 1489,  479,  476,  475,    6,  163,  544,
 /*   580 */   510,  544,  115,  422,  474,    5,  121,  122,  112, 1162,
 /*   590 */  1162, 1003, 1006,  996,  996,  119,  119,  120,  120,  120,
 /*   600 */   120,   13,   13,   13,   13,  118,  118,  118,  118,  117,
 /*   610 */   117,  116,  116,  116,  115,  422,  401,  500,  406,  544,
 /*   620 */  1483,  542, 1139,  889,  889, 1139, 1140, 1141, 1470, 1139,
 /*   630 */   275,  390,  805,  806,  807,  968,  420,  420,  420,   16,
 /*   640 */    16,   55,   55, 1239,  118,  118,  118,  118,  117,  117,
 /*   650 */   116,  116,  116,  115,  422,  121,  122,  112, 1162, 1162,
 /*   660 */  1003, 1006,  996,  996,  119,  119,  120,  120,  120,  120,
 /*   670 */   390, 1186,    1,    1,  549,    2, 1190, 1139, 1140, 1141,
 /*   680 */   194,  291,  895,  136, 1139, 1140, 1141,  894,  519, 1489,
 /*   690 */  1270,    3,  378,    6,  121,  122,  112, 1162, 1162, 1003,
 /*   700 */  1006,  996,  996,  119,  119,  120,  120,  120,  120,  855,
 /*   710 */   544,  921,  544,  118,  118,  118,  118,  117,  117,  116,
 /*   720 */   116,  116,  115,  422,  266,  266, 1089, 1566, 1139, 1518,
 /*   730 */  1566, 1190,   13,   13,   13,   13,  291,  541,  136,  390,
 /*   740 */   483,  419,  418,  963,  342, 1270,  466,  408,  856,  279,
 /*   750 */   140,  221,  118,  118,  118,  118,  117,  117,  116,  116,
 /*   760 */   116,  115,  422,  121,  122,  112, 1162, 1162, 1003, 1006,
 /*   770 */   996,  996,  119,  119,  120,  120,  120,  120,  544,  266,
 /*   780 */   266,  426,  390, 1139, 1140, 1141, 1169,  827, 1169,  466,
 /*   790 */   429,  145,  541, 1143,  399,  313,  437,  301,  835, 1487,
 /*   800 */    71,   71,  410,    6, 1087,  471,  221,  100,  112, 1162,
 /*   810 */  1162, 1003, 1006,  996,  996,  119,  119,  120,  120,  120,
 /*   820 */   120,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   830 */   115,  422,  237, 1422,  544,  449,  426,  287,  983,  544,
 /*   840 */   236,  235,  234,  827,   97,  527,  427, 1262, 1262, 1143,
 /*   850 */   492,  306,  428,  835,  974,  544,   71,   71,  973, 1238,
 /*   860 */   544,   51,   51,  300,  118,  118,  118,  118,  117,  117,
 /*   870 */   116,  116,  116,  115,  422,  194,  103,   70,   70,  266,
 /*   880 */   266,  544,   71,   71,  266,  266,   30,  389,  342,  973,
 /*   890 */   973,  975,  541,  526, 1106,  326,  390,  541,  493,  395,
 /*   900 */  1467,  195,  528,   13,   13, 1355,  240, 1106,  277,  280,
 /*   910 */  1106,  280,  303,  455,  305,  331,  390,   31,  188,  417,
 /*   920 */   121,  122,  112, 1162, 1162, 1003, 1006,  996,  996,  119,
 /*   930 */   119,  120,  120,  120,  120,  142,  390,  363,  455,  983,
 /*   940 */   121,  122,  112, 1162, 1162, 1003, 1006,  996,  996,  119,
 /*   950 */   119,  120,  120,  120,  120,  974,  321, 1139,  324,  973,
 /*   960 */   121,  110,  112, 1162, 1162, 1003, 1006,  996,  996,  119,
 /*   970 */   119,  120,  120,  120,  120,  462,  375, 1182,  118,  118,
 /*   980 */   118,  118,  117,  117,  116,  116,  116,  115,  422, 1139,
 /*   990 */   973,  973,  975,  304,    9,  364,  244,  360,  118,  118,
 /*  1000 */   118,  118,  117,  117,  116,  116,  116,  115,  422,  312,
 /*  1010 */   544,  342, 1139, 1140, 1141,  299,  290,  535,  118,  118,
 /*  1020 */   118,  118,  117,  117,  116,  116,  116,  115,  422, 1260,
 /*  1030 */  1260, 1160,   13,   13,  278,  419,  418,  466,  390,  920,
 /*  1040 */   260,  260,  289, 1166, 1139, 1140, 1141,  189, 1168,  266,
 /*  1050 */   266,  466,  388,  541, 1183,  544, 1167,  263,  144,  487,
 /*  1060 */   919,  544,  541,  122,  112, 1162, 1162, 1003, 1006,  996,
 /*  1070 */   996,  119,  119,  120,  120,  120,  120,   71,   71, 1139,
 /*  1080 */  1169, 1269, 1169,   13,   13,  895, 1067, 1160,  544,  466,
 /*  1090 */   894,  107,  536, 1488,    4, 1265, 1106,    6,  523, 1046,
 /*  1100 */    12, 1068, 1089, 1567,  311,  453, 1567,  518,  539, 1106,
 /*  1110 */    56,   56, 1106, 1486,  421, 1355, 1069,    6,  343,  285,
 /*  1120 */   118,  118,  118,  118,  117,  117,  116,  116,  116,  115,
 /*  1130 */   422,  423, 1268,  319, 1139, 1140, 1141,  875,  266,  266,
 /*  1140 */  1274,  107,  536,  533,    4, 1485,  293,  876, 1208,    6,
 /*  1150 */   210,  541,  541,  164, 1539,  494,  414,  864,  539,  267,
 /*  1160 */   267, 1211,  396,  509,  497,  204,  266,  266,  394,  529,
 /*  1170 */     8,  983,  541,  517,  544,  919,  456,  105,  105,  541,
 /*  1180 */  1087,  423,  266,  266,  106,  415,  423,  546,  545,  266,
 /*  1190 */   266,  973,  516,  533, 1370,  541,   15,   15,  266,  266,
 /*  1200 */   454, 1117,  541,  266,  266, 1067, 1369,  513,  290,  535,
 /*  1210 */   544,  541,  512,   97,  442,  314,  541,  544,  919,  125,
 /*  1220 */  1068,  983,  973,  973,  975,  976,   27,  105,  105,  399,
 /*  1230 */   341, 1508,   44,   44,  106, 1069,  423,  546,  545,   57,
 /*  1240 */    57,  973,  341, 1508,  107,  536,  544,    4,  460,  399,
 /*  1250 */   214, 1117,  457,  294,  375, 1088,  532,  297,  544,  537,
 /*  1260 */   396,  539,  290,  535,  104,  244,  102,  524,   58,   58,
 /*  1270 */   544,  109,  973,  973,  975,  976,   27, 1513, 1128,  425,
 /*  1280 */    59,   59,  270,  237,  423,  138,   95,  373,  373,  372,
 /*  1290 */   255,  370,   60,   60,  814, 1177,  533,  544,  273,  544,
 /*  1300 */  1160,  842,  387,  386,  544, 1306,  544,  215,  210,  296,
 /*  1310 */   513,  846,  544,  265,  208,  514, 1305,  295,  274,   61,
 /*  1320 */    61,   62,   62,  436,  983, 1159,   45,   45,   46,   46,
 /*  1330 */   105,  105, 1183,  919,   47,   47, 1473,  106,  544,  423,
 /*  1340 */   546,  545,  218,  544,  973,  934, 1084,  217,  544,  377,
 /*  1350 */   395,  107,  536,  935,    4,  156, 1160,  842,  158,  544,
 /*  1360 */    49,   49,  141,  544,   38,   50,   50,  544,  539,  307,
 /*  1370 */    63,   63,  544, 1447,  216,  973,  973,  975,  976,   27,
 /*  1380 */   444,   64,   64,  544, 1446,   65,   65,  544,  524,   14,
 /*  1390 */    14,  423,  458,  544,   66,   66,  310,  544,  316,   97,
 /*  1400 */  1033,  544,  960,  533,  268,  127,  127,  544,  391,   67,
 /*  1410 */    67,  544,  977,  290,  535,   52,   52,  513,  544,   68,
 /*  1420 */    68, 1293,  512,   69,   69,  397,  165,  854,  853,   53,
 /*  1430 */    53,  983,  965,  151,  151,  243,  430,  105,  105,  199,
 /*  1440 */   152,  152,  448, 1302,  106,  243,  423,  546,  545, 1128,
 /*  1450 */   425,  973,  320,  270,  861,  862, 1033,  220,  373,  373,
 /*  1460 */   372,  255,  370,  450,  323,  814,  243,  544,  977,  544,
 /*  1470 */   107,  536,  544,    4,  544,  937,  938,  325,  215, 1045,
 /*  1480 */   296, 1045,  973,  973,  975,  976,   27,  539,  295,   76,
 /*  1490 */    76,   54,   54,  327,   72,   72,  128,  128, 1502, 1253,
 /*  1500 */   107,  536,  544,    4, 1044,  544, 1044,  531, 1237,  544,
 /*  1510 */   423,  544,  315,  334,  544,   97,  544,  539,  217,  544,
 /*  1520 */   472, 1527,  533,  239,   73,   73,  156,  129,  129,  158,
 /*  1530 */   467,  130,  130,  126,  126,  344,  150,  150,  149,  149,
 /*  1540 */   423,  134,  134,  329, 1029,  216,   97,  239,  928,  345,
 /*  1550 */   983,  243,  533, 1314,  339,  544,  105,  105,  899, 1354,
 /*  1560 */   544, 1289,  258,  106,  338,  423,  546,  545,  544, 1300,
 /*  1570 */   973,  892,   99,  536,  109,    4,  544,  133,  133,  391,
 /*  1580 */   983,  197,  131,  131,  290,  535,  105,  105,  530,  539,
 /*  1590 */   132,  132, 1360,  106, 1218,  423,  546,  545,   75,   75,
 /*  1600 */   973,  973,  973,  975,  976,   27,  544,  430,  825, 1210,
 /*  1610 */   893,  139,  423,  109,  544, 1199, 1198, 1200, 1521,  544,
 /*  1620 */   201,  544,   11,  374,  533, 1286,  347,  349,   77,   77,
 /*  1630 */  1339,  973,  973,  975,  976,   27,   74,   74,  351,  213,
 /*  1640 */   435,   43,   43,   48,   48,  302,  477,  309, 1347,  382,
 /*  1650 */   353,  452,  983,  337, 1236, 1419, 1418,  205,  105,  105,
 /*  1660 */   192,  367,  193,  534, 1524,  106, 1177,  423,  546,  545,
 /*  1670 */   247,  167,  973,  270, 1466,  200, 1464, 1174,  373,  373,
 /*  1680 */   372,  255,  370,  398,   79,  814,   83,   82, 1424,  446,
 /*  1690 */   161,  177,  169,   95, 1336,  438,  172,  173,  215,  174,
 /*  1700 */   296,  175,   35,  973,  973,  975,  976,   27,  295, 1344,
 /*  1710 */   439,  470,  223,   36,  379,  445, 1413,  381,  459, 1350,
 /*  1720 */   181,  227,   88,  465,  259,  229, 1435,  318,  186,  468,
 /*  1730 */   322,  230,  384, 1201,  231,  486, 1256, 1255,  217,  411,
 /*  1740 */  1254, 1247,   90,  846,  206,  413,  156,  505, 1538,  158,
 /*  1750 */  1225, 1537,  283, 1507, 1226,  336,  385,  284, 1224,  496,
 /*  1760 */  1536, 1297,   94,  346,  348,  216, 1246,  499, 1298,  245,
 /*  1770 */   246, 1296,  416,  350, 1493,  124, 1492,   10,  524,  361,
 /*  1780 */  1399,  101,   96,  288,  508,  253, 1134, 1207,   34, 1295,
 /*  1790 */   547,  254,  256,  257,  392,  548, 1196, 1191,  359,  391,
 /*  1800 */  1279, 1278,  196,  365,  290,  535,  366,  352, 1451, 1321,
 /*  1810 */  1320, 1452,  153,  137,  281,  154,  801,  424,  155, 1450,
 /*  1820 */  1449,  198,  292,  202,  203,   78,  212,  430,  271,  135,
 /*  1830 */  1043, 1041,  957,  168,  219,  157,  170,  878,  308,  222,
 /*  1840 */  1057,  176,  159,  961,  400,   84,  402,  178,   85,   86,
 /*  1850 */    87,  166,  160,  393, 1060,  224,  225, 1056,  146,   18,
 /*  1860 */   226,  317, 1049, 1171,  243,  464,  182,  228,   37,  183,
 /*  1870 */   816,  469,  338,  232,  330,  481,  184,   89,  844,   19,
 /*  1880 */    20,   92,  473,  478,  333,   91,  162,  857,  147,  488,
 /*  1890 */   282, 1122,  148, 1009,  927, 1092,   39,   93,   40,  495,
 /*  1900 */  1093,  187,  498,  207,  262,  264,  922,  242, 1108,  109,
 /*  1910 */  1112, 1110, 1096,   33,   21, 1116,  520, 1024,   22,   23,
 /*  1920 */    24, 1115,   25,  190,   97, 1010, 1008,   26, 1012, 1066,
 /*  1930 */   248,    7, 1065,  249, 1013,   28,   41,  888,  978,  826,
 /*  1940 */   108,   29,  250,  540,  251, 1529,  371,  368, 1129, 1187,
 /*  1950 */  1187, 1187, 1187, 1187, 1187, 1187, 1187, 1528,
};
static const YYCODETYPE yy_lookahead[] = {
 /*     0 */   189,  211,  189,  189,  218,  189,  220,  189,  267,  268,
 /*    10 */   269,  189,  210,  189,  228,  189,  267,  268,  269,   19,
 /*    20 */   218,  189,  211,  212,  211,  212,  211,  211,  212,  211,
 /*    30 */   212,   31,  211,  211,  212,  211,  212,  288,  300,   39,
 /*    40 */    21,  189,  304,   43,   44,   45,   46,   47,   48,   49,







|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|


|
|
|
|
|

|
|

|
|
|

|
|
|

|
|

|
|
|

|
|
|

|

|
|
|


|
|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|

|
|
|


|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|
|

|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







152829
152830
152831
152832
152833
152834
152835
152836
152837
152838
152839
152840
152841
152842
152843
152844
152845
152846
152847
152848
152849
152850
152851
152852
152853
152854
152855
152856
152857
152858
152859
152860
152861
152862
152863
152864
152865
152866
152867
152868
152869
152870
152871
152872
152873
152874
152875
152876
152877
152878
152879
152880
152881
152882
152883
152884
152885
152886
152887
152888
152889
152890
152891
152892
152893
152894
152895
152896
152897
152898
152899
152900
152901
152902
152903
152904
152905
152906
152907
152908
152909
152910
152911
152912
152913
152914
152915
152916
152917
152918
152919
152920
152921
152922
152923
152924
152925
152926
152927
152928
152929
152930
152931
152932
152933
152934
152935
152936
152937
152938
152939
152940
152941
152942
152943
152944
152945
152946
152947
152948
152949
152950
152951
152952
152953
152954
152955
152956
152957
152958
152959
152960
152961
152962
152963
152964
152965
152966
152967
152968
152969
152970
152971
152972
152973
152974
152975
152976
152977
152978
152979
152980
152981
152982
152983
152984
152985
152986
152987
152988
152989
152990
152991
152992
152993
152994
152995
152996
152997
152998
152999
153000
153001
153002
153003
153004
153005
153006
153007
153008
153009
153010
153011
153012
153013
153014
153015
153016
153017
153018
153019
153020
153021
153022
153023
153024
153025
153026
153027
153028
153029
153030
153031
153032
153033
153034
153035
153036
153037
153038
**  yy_reduce_ofst[]   For each state, the offset into yy_action for
**                     shifting non-terminals after a reduce.
**  yy_default[]       Default action for each state.
**
*********** Begin parsing tables **********************************************/
#define YY_ACTTAB_COUNT (1958)
static const YYACTIONTYPE yy_action[] = {
 /*     0 */   544, 1220,  544,  449, 1258,  544, 1237,  544,  114,  111,
 /*    10 */   211,  544, 1535,  544, 1258,  521,  114,  111,  211,  390,
 /*    20 */  1230,  342,   42,   42,   42,   42, 1223,   42,   42,   71,
 /*    30 */    71,  935, 1222,   71,   71,   71,   71, 1460, 1491,  936,
 /*    40 */   818,  451,    6,  121,  122,  112, 1163, 1163, 1004, 1007,
 /*    50 */   997,  997,  119,  119,  120,  120,  120,  120, 1541,  390,
 /*    60 */  1356, 1515,  550,    2, 1191,  194,  526,  434,  143,  291,
 /*    70 */   526,  136,  526,  369,  261,  502,  272,  383, 1271,  525,
 /*    80 */   501,  491,  164,  121,  122,  112, 1163, 1163, 1004, 1007,
 /*    90 */   997,  997,  119,  119,  120,  120,  120,  120, 1356,  440,
 /*   100 */  1512,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   110 */   115,  422,  266,  266,  266,  266, 1496,  356, 1498,  433,
 /*   120 */   355, 1496,  515,  522, 1483,  541, 1112,  541, 1112,  390,
 /*   130 */   403,  241,  208,  114,  111,  211,   98,  290,  535,  221,
 /*   140 */  1027,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   150 */   115,  422, 1140,  121,  122,  112, 1163, 1163, 1004, 1007,
 /*   160 */   997,  997,  119,  119,  120,  120,  120,  120,  404,  426,
 /*   170 */   117,  117,  116,  116,  116,  115,  422, 1416,  466,  123,
 /*   180 */   118,  118,  118,  118,  117,  117,  116,  116,  116,  115,
 /*   190 */   422,  116,  116,  116,  115,  422,  538,  538,  538,  390,
 /*   200 */   503,  120,  120,  120,  120,  113, 1049, 1140, 1141, 1142,
 /*   210 */  1049,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   220 */   115,  422, 1459,  121,  122,  112, 1163, 1163, 1004, 1007,
 /*   230 */   997,  997,  119,  119,  120,  120,  120,  120,  390,  442,
 /*   240 */   314,   83,  461,   81,  357,  380, 1140,   80,  118,  118,
 /*   250 */   118,  118,  117,  117,  116,  116,  116,  115,  422,  179,
 /*   260 */   432,  422,  121,  122,  112, 1163, 1163, 1004, 1007,  997,
 /*   270 */   997,  119,  119,  120,  120,  120,  120,  432,  431,  266,
 /*   280 */   266,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   290 */   115,  422,  541, 1107,  901,  504, 1140,  114,  111,  211,
 /*   300 */  1429, 1140, 1141, 1142,  206,  489, 1107,  390,  447, 1107,
 /*   310 */   543,  328,  120,  120,  120,  120,  298, 1429, 1431,   17,
 /*   320 */   118,  118,  118,  118,  117,  117,  116,  116,  116,  115,
 /*   330 */   422,  121,  122,  112, 1163, 1163, 1004, 1007,  997,  997,
 /*   340 */   119,  119,  120,  120,  120,  120,  390, 1356,  432, 1140,
 /*   350 */   480, 1140, 1141, 1142,  994,  994, 1005, 1008,  443,  118,
 /*   360 */   118,  118,  118,  117,  117,  116,  116,  116,  115,  422,
 /*   370 */   121,  122,  112, 1163, 1163, 1004, 1007,  997,  997,  119,
 /*   380 */   119,  120,  120,  120,  120, 1052, 1052,  463, 1429,  118,
 /*   390 */   118,  118,  118,  117,  117,  116,  116,  116,  115,  422,
 /*   400 */  1140,  449,  544, 1424, 1140, 1141, 1142,  233,  964, 1140,
 /*   410 */   479,  476,  475,  171,  358,  390,  164,  405,  412,  840,
 /*   420 */   474,  164,  185,  332,   71,   71, 1241,  998,  118,  118,
 /*   430 */   118,  118,  117,  117,  116,  116,  116,  115,  422,  121,
 /*   440 */   122,  112, 1163, 1163, 1004, 1007,  997,  997,  119,  119,
 /*   450 */   120,  120,  120,  120,  390, 1140, 1141, 1142,  833,   12,
 /*   460 */   313,  507,  163,  354, 1140, 1141, 1142,  114,  111,  211,
 /*   470 */   506,  290,  535,  544,  276,  180,  290,  535,  121,  122,
 /*   480 */   112, 1163, 1163, 1004, 1007,  997,  997,  119,  119,  120,
 /*   490 */   120,  120,  120,  343,  482,   71,   71,  118,  118,  118,
 /*   500 */   118,  117,  117,  116,  116,  116,  115,  422, 1140,  209,
 /*   510 */   409,  521, 1140, 1107, 1569,  376,  252,  269,  340,  485,
 /*   520 */   335,  484,  238,  390,  511,  362, 1107, 1125,  331, 1107,
 /*   530 */   191,  407,  286,   32,  455,  441,  118,  118,  118,  118,
 /*   540 */   117,  117,  116,  116,  116,  115,  422,  121,  122,  112,
 /*   550 */  1163, 1163, 1004, 1007,  997,  997,  119,  119,  120,  120,
 /*   560 */   120,  120,  390, 1140, 1141, 1142,  985, 1140, 1141, 1142,
 /*   570 */  1140,  233,  490, 1490,  479,  476,  475,    6,  163,  544,
 /*   580 */   510,  544,  115,  422,  474,    5,  121,  122,  112, 1163,
 /*   590 */  1163, 1004, 1007,  997,  997,  119,  119,  120,  120,  120,
 /*   600 */   120,   13,   13,   13,   13,  118,  118,  118,  118,  117,
 /*   610 */   117,  116,  116,  116,  115,  422,  401,  500,  406,  544,
 /*   620 */  1484,  542, 1140,  890,  890, 1140, 1141, 1142, 1471, 1140,
 /*   630 */   275,  390,  806,  807,  808,  969,  420,  420,  420,   16,
 /*   640 */    16,   55,   55, 1240,  118,  118,  118,  118,  117,  117,
 /*   650 */   116,  116,  116,  115,  422,  121,  122,  112, 1163, 1163,
 /*   660 */  1004, 1007,  997,  997,  119,  119,  120,  120,  120,  120,
 /*   670 */   390, 1187,    1,    1,  550,    2, 1191, 1140, 1141, 1142,
 /*   680 */   194,  291,  896,  136, 1140, 1141, 1142,  895,  519, 1490,
 /*   690 */  1271,    3,  378,    6,  121,  122,  112, 1163, 1163, 1004,
 /*   700 */  1007,  997,  997,  119,  119,  120,  120,  120,  120,  856,
 /*   710 */   544,  922,  544,  118,  118,  118,  118,  117,  117,  116,
 /*   720 */   116,  116,  115,  422,  266,  266, 1090, 1567, 1140,  549,
 /*   730 */  1567, 1191,   13,   13,   13,   13,  291,  541,  136,  390,
 /*   740 */   483,  419,  418,  964,  342, 1271,  466,  408,  857,  279,
 /*   750 */   140,  221,  118,  118,  118,  118,  117,  117,  116,  116,
 /*   760 */   116,  115,  422,  121,  122,  112, 1163, 1163, 1004, 1007,
 /*   770 */   997,  997,  119,  119,  120,  120,  120,  120,  544,  266,
 /*   780 */   266,  426,  390, 1140, 1141, 1142, 1170,  828, 1170,  466,
 /*   790 */   429,  145,  541, 1144,  399,  313,  437,  301,  836, 1488,
 /*   800 */    71,   71,  410,    6, 1088,  471,  221,  100,  112, 1163,
 /*   810 */  1163, 1004, 1007,  997,  997,  119,  119,  120,  120,  120,
 /*   820 */   120,  118,  118,  118,  118,  117,  117,  116,  116,  116,
 /*   830 */   115,  422,  237, 1423,  544,  449,  426,  287,  984,  544,
 /*   840 */   236,  235,  234,  828,   97,  527,  427, 1263, 1263, 1144,
 /*   850 */   492,  306,  428,  836,  975,  544,   71,   71,  974, 1239,
 /*   860 */   544,   51,   51,  300,  118,  118,  118,  118,  117,  117,
 /*   870 */   116,  116,  116,  115,  422,  194,  103,   70,   70,  266,
 /*   880 */   266,  544,   71,   71,  266,  266,   30,  389,  342,  974,
 /*   890 */   974,  976,  541,  526, 1107,  326,  390,  541,  493,  395,
 /*   900 */  1468,  195,  528,   13,   13, 1356,  240, 1107,  277,  280,
 /*   910 */  1107,  280,  303,  455,  305,  331,  390,   31,  188,  417,
 /*   920 */   121,  122,  112, 1163, 1163, 1004, 1007,  997,  997,  119,
 /*   930 */   119,  120,  120,  120,  120,  142,  390,  363,  455,  984,
 /*   940 */   121,  122,  112, 1163, 1163, 1004, 1007,  997,  997,  119,
 /*   950 */   119,  120,  120,  120,  120,  975,  321, 1140,  324,  974,
 /*   960 */   121,  110,  112, 1163, 1163, 1004, 1007,  997,  997,  119,
 /*   970 */   119,  120,  120,  120,  120,  462,  375, 1183,  118,  118,
 /*   980 */   118,  118,  117,  117,  116,  116,  116,  115,  422, 1140,
 /*   990 */   974,  974,  976,  304,    9,  364,  244,  360,  118,  118,
 /*  1000 */   118,  118,  117,  117,  116,  116,  116,  115,  422,  312,
 /*  1010 */   544,  342, 1140, 1141, 1142,  299,  290,  535,  118,  118,
 /*  1020 */   118,  118,  117,  117,  116,  116,  116,  115,  422, 1261,
 /*  1030 */  1261, 1161,   13,   13,  278,  419,  418,  466,  390,  921,
 /*  1040 */   260,  260,  289, 1167, 1140, 1141, 1142,  189, 1169,  266,
 /*  1050 */   266,  466,  388,  541, 1184,  544, 1168,  263,  144,  487,
 /*  1060 */   920,  544,  541,  122,  112, 1163, 1163, 1004, 1007,  997,
 /*  1070 */   997,  119,  119,  120,  120,  120,  120,   71,   71, 1140,
 /*  1080 */  1170, 1270, 1170,   13,   13,  896, 1068, 1161,  544,  466,
 /*  1090 */   895,  107,  536, 1489,    4, 1266, 1107,    6,  523, 1047,
 /*  1100 */    12, 1069, 1090, 1568,  311,  453, 1568,  518,  539, 1107,
 /*  1110 */    56,   56, 1107, 1487,  421, 1356, 1070,    6,  343,  285,
 /*  1120 */   118,  118,  118,  118,  117,  117,  116,  116,  116,  115,
 /*  1130 */   422,  423, 1269,  319, 1140, 1141, 1142,  876,  266,  266,
 /*  1140 */  1275,  107,  536,  533,    4, 1486,  293,  877, 1209,    6,
 /*  1150 */   210,  541,  541,  164, 1540,  494,  414,  865,  539,  267,
 /*  1160 */   267, 1212,  396,  509,  497,  204,  266,  266,  394,  529,
 /*  1170 */     8,  984,  541,  517,  544,  920,  456,  105,  105,  541,
 /*  1180 */  1088,  423,  266,  266,  106,  415,  423,  546,  545,  266,
 /*  1190 */   266,  974,  516,  533, 1371,  541,   15,   15,  266,  266,
 /*  1200 */   454, 1118,  541,  266,  266, 1068, 1370,  513,  290,  535,
 /*  1210 */   544,  541,  512,   97,  442,  314,  541,  544,  920,  125,
 /*  1220 */  1069,  984,  974,  974,  976,  977,   27,  105,  105,  399,
 /*  1230 */   341, 1509,   44,   44,  106, 1070,  423,  546,  545,   57,
 /*  1240 */    57,  974,  341, 1509,  107,  536,  544,    4,  460,  399,
 /*  1250 */   214, 1118,  457,  294,  375, 1089,  532,  297,  544,  537,
 /*  1260 */   396,  539,  290,  535,  104,  244,  102,  524,   58,   58,
 /*  1270 */   544,  109,  974,  974,  976,  977,   27, 1514, 1129,  425,
 /*  1280 */    59,   59,  270,  237,  423,  138,   95,  373,  373,  372,
 /*  1290 */   255,  370,   60,   60,  815, 1178,  533,  544,  273,  544,
 /*  1300 */  1161,  843,  387,  386,  544, 1307,  544,  215,  210,  296,
 /*  1310 */   513,  847,  544,  265,  208,  514, 1306,  295,  274,   61,
 /*  1320 */    61,   62,   62,  436,  984, 1160,   45,   45,   46,   46,
 /*  1330 */   105,  105, 1184,  920,   47,   47, 1474,  106,  544,  423,
 /*  1340 */   546,  545,  218,  544,  974,  935, 1085,  217,  544,  377,
 /*  1350 */   395,  107,  536,  936,    4,  156, 1161,  843,  158,  544,
 /*  1360 */    49,   49,  141,  544,   38,   50,   50,  544,  539,  307,
 /*  1370 */    63,   63,  544, 1448,  216,  974,  974,  976,  977,   27,
 /*  1380 */   444,   64,   64,  544, 1447,   65,   65,  544,  524,   14,
 /*  1390 */    14,  423,  458,  544,   66,   66,  310,  544,  316,   97,
 /*  1400 */  1034,  544,  961,  533,  268,  127,  127,  544,  391,   67,
 /*  1410 */    67,  544,  978,  290,  535,   52,   52,  513,  544,   68,
 /*  1420 */    68, 1294,  512,   69,   69,  397,  165,  855,  854,   53,
 /*  1430 */    53,  984,  966,  151,  151,  243,  430,  105,  105,  199,
 /*  1440 */   152,  152,  448, 1303,  106,  243,  423,  546,  545, 1129,
 /*  1450 */   425,  974,  320,  270,  862,  863, 1034,  220,  373,  373,
 /*  1460 */   372,  255,  370,  450,  323,  815,  243,  544,  978,  544,
 /*  1470 */   107,  536,  544,    4,  544,  938,  939,  325,  215, 1046,
 /*  1480 */   296, 1046,  974,  974,  976,  977,   27,  539,  295,   76,
 /*  1490 */    76,   54,   54,  327,   72,   72,  128,  128, 1503, 1254,
 /*  1500 */   107,  536,  544,    4, 1045,  544, 1045,  531, 1238,  544,
 /*  1510 */   423,  544,  315,  334,  544,   97,  544,  539,  217,  544,
 /*  1520 */   472, 1528,  533,  239,   73,   73,  156,  129,  129,  158,
 /*  1530 */   467,  130,  130,  126,  126,  344,  150,  150,  149,  149,
 /*  1540 */   423,  134,  134,  329, 1030,  216,   97,  239,  929,  345,
 /*  1550 */   984,  243,  533, 1315,  339,  544,  105,  105,  900, 1355,
 /*  1560 */   544, 1290,  258,  106,  338,  423,  546,  545,  544, 1301,
 /*  1570 */   974,  893,   99,  536,  109,    4,  544,  133,  133,  391,
 /*  1580 */   984,  197,  131,  131,  290,  535,  105,  105,  530,  539,
 /*  1590 */   132,  132, 1361,  106, 1219,  423,  546,  545,   75,   75,
 /*  1600 */   974,  974,  974,  976,  977,   27,  544,  430,  826, 1211,
 /*  1610 */   894,  139,  423,  109,  544, 1200, 1199, 1201, 1522,  544,
 /*  1620 */   201,  544,   11,  374,  533, 1287,  347,  349,   77,   77,
 /*  1630 */  1340,  974,  974,  976,  977,   27,   74,   74,  351,  213,
 /*  1640 */   435,   43,   43,   48,   48,  302,  477,  309, 1348,  382,
 /*  1650 */   353,  452,  984,  337, 1237, 1420, 1419,  205,  105,  105,
 /*  1660 */   192,  367,  193,  534, 1525,  106, 1178,  423,  546,  545,
 /*  1670 */   247,  167,  974,  270, 1467,  200, 1465, 1175,  373,  373,
 /*  1680 */   372,  255,  370,  398,   79,  815,   83,   82, 1425,  446,
 /*  1690 */   161,  177,  169,   95, 1337,  438,  172,  173,  215,  174,
 /*  1700 */   296,  175,   35,  974,  974,  976,  977,   27,  295, 1345,
 /*  1710 */   439,  470,  223,   36,  379,  445, 1414,  381,  459, 1351,
 /*  1720 */   181,  227,   88,  465,  259,  229, 1436,  318,  186,  468,
 /*  1730 */   322,  230,  384, 1202,  231,  486, 1257, 1256,  217,  411,
 /*  1740 */  1255, 1248,   90,  847,  206,  413,  156,  505, 1539,  158,
 /*  1750 */  1226, 1538,  283, 1508, 1227,  336,  385,  284, 1225,  496,
 /*  1760 */  1537, 1298,   94,  346,  348,  216, 1247,  499, 1299,  245,
 /*  1770 */   246, 1297,  416,  350, 1494,  124, 1493,   10,  524,  361,
 /*  1780 */  1400,  101,   96,  288,  508,  253, 1135, 1208,   34, 1296,
 /*  1790 */   547,  254,  256,  257,  392,  548, 1197, 1192,  359,  391,
 /*  1800 */  1280, 1279,  196,  365,  290,  535,  366,  352, 1452, 1322,
 /*  1810 */  1321, 1453,  153,  137,  281,  154,  802,  424,  155, 1451,
 /*  1820 */  1450,  198,  292,  202,  203,   78,  212,  430,  271,  135,
 /*  1830 */  1044, 1042,  958,  168,  219,  157,  170,  879,  308,  222,
 /*  1840 */  1058,  176,  159,  962,  400,   84,  402,  178,   85,   86,
 /*  1850 */    87,  166,  160,  393, 1061,  224,  225, 1057,  146,   18,
 /*  1860 */   226,  317, 1050, 1172,  243,  464,  182,  228,   37,  183,
 /*  1870 */   817,  469,  338,  232,  330,  481,  184,   89,  845,   19,
 /*  1880 */    20,   92,  473,  478,  333,   91,  162,  858,  147,  488,
 /*  1890 */   282, 1123,  148, 1010,  928, 1093,   39,   93,   40,  495,
 /*  1900 */  1094,  187,  498,  207,  262,  264,  923,  242, 1109,  109,
 /*  1910 */  1113, 1111, 1097,   33,   21, 1117,  520, 1025,   22,   23,
 /*  1920 */    24, 1116,   25,  190,   97, 1011, 1009,   26, 1013, 1067,
 /*  1930 */   248,    7, 1066,  249, 1014,   28,   41,  889,  979,  827,
 /*  1940 */   108,   29,  250,  540,  251, 1530,  371,  368, 1131, 1130,
 /*  1950 */  1188, 1188, 1188, 1188, 1188, 1188, 1188, 1529,
};
static const YYCODETYPE yy_lookahead[] = {
 /*     0 */   189,  211,  189,  189,  218,  189,  220,  189,  267,  268,
 /*    10 */   269,  189,  210,  189,  228,  189,  267,  268,  269,   19,
 /*    20 */   218,  189,  211,  212,  211,  212,  211,  211,  212,  211,
 /*    30 */   212,   31,  211,  211,  212,  211,  212,  288,  300,   39,
 /*    40 */    21,  189,  304,   43,   44,   45,   46,   47,   48,   49,
151502
151503
151504
151505
151506
151507
151508
151509
151510
151511
151512
151513
151514
151515
151516
151517
151518
151519
151520
151521
151522
151523
151524
151525
151526
151527
151528
151529
151530
151531
151532
151533
151534
151535
151536
151537
151538
151539
 /*  1870 */    20,   19,  129,  123,   23,   96,   22,   22,   59,   22,
 /*  1880 */    22,  147,   67,   67,   24,   22,   37,   28,   23,   22,
 /*  1890 */    67,   23,   23,   23,  114,   23,   22,   26,   22,   24,
 /*  1900 */    23,   22,   24,  139,   23,   23,  141,   34,   88,   26,
 /*  1910 */    75,   86,   23,   22,   34,   75,   24,   23,   34,   34,
 /*  1920 */    34,   93,   34,   26,   26,   23,   23,   34,   23,   23,
 /*  1930 */    26,   44,   23,   22,   11,   22,   22,  133,   23,   23,
 /*  1940 */    22,   22,  139,   26,  139,  139,   15,   23,    1,  310,
 /*  1950 */   310,  310,  310,  310,  310,  310,  310,  139,  310,  310,
 /*  1960 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  1970 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  1980 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  1990 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2000 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2010 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2020 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2030 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2040 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2050 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2060 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2070 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2080 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2090 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2100 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2110 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2120 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2130 */   310,  310,  310,  310,  310,  310,  310,  310,  310,
};
#define YY_SHIFT_COUNT    (549)
#define YY_SHIFT_MIN      (0)
#define YY_SHIFT_MAX      (1947)
static const unsigned short int yy_shift_ofst[] = {
 /*     0 */  1448, 1277, 1668, 1072, 1072,  340, 1122, 1225, 1332, 1481,
 /*    10 */  1481, 1481,  335,    0,    0,  180,  897, 1481, 1481, 1481,
 /*    20 */  1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
 /*    30 */   930,  930, 1020, 1020,  290,    1,  340,  340,  340,  340,
 /*    40 */   340,  340,   40,  110,  219,  288,  327,  396,  435,  504,
 /*    50 */   543,  612,  651,  720,  877,  897,  897,  897,  897,  897,







|




















|

|







153221
153222
153223
153224
153225
153226
153227
153228
153229
153230
153231
153232
153233
153234
153235
153236
153237
153238
153239
153240
153241
153242
153243
153244
153245
153246
153247
153248
153249
153250
153251
153252
153253
153254
153255
153256
153257
153258
 /*  1870 */    20,   19,  129,  123,   23,   96,   22,   22,   59,   22,
 /*  1880 */    22,  147,   67,   67,   24,   22,   37,   28,   23,   22,
 /*  1890 */    67,   23,   23,   23,  114,   23,   22,   26,   22,   24,
 /*  1900 */    23,   22,   24,  139,   23,   23,  141,   34,   88,   26,
 /*  1910 */    75,   86,   23,   22,   34,   75,   24,   23,   34,   34,
 /*  1920 */    34,   93,   34,   26,   26,   23,   23,   34,   23,   23,
 /*  1930 */    26,   44,   23,   22,   11,   22,   22,  133,   23,   23,
 /*  1940 */    22,   22,  139,   26,  139,  139,   15,   23,    1,    1,
 /*  1950 */   310,  310,  310,  310,  310,  310,  310,  139,  310,  310,
 /*  1960 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  1970 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  1980 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  1990 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2000 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2010 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2020 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2030 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2040 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2050 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2060 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2070 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2080 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2090 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2100 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2110 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2120 */   310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
 /*  2130 */   310,  310,  310,  310,  310,  310,  310,  310,  310,
};
#define YY_SHIFT_COUNT    (550)
#define YY_SHIFT_MIN      (0)
#define YY_SHIFT_MAX      (1948)
static const unsigned short int yy_shift_ofst[] = {
 /*     0 */  1448, 1277, 1668, 1072, 1072,  340, 1122, 1225, 1332, 1481,
 /*    10 */  1481, 1481,  335,    0,    0,  180,  897, 1481, 1481, 1481,
 /*    20 */  1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
 /*    30 */   930,  930, 1020, 1020,  290,    1,  340,  340,  340,  340,
 /*    40 */   340,  340,   40,  110,  219,  288,  327,  396,  435,  504,
 /*    50 */   543,  612,  651,  720,  877,  897,  897,  897,  897,  897,
151582
151583
151584
151585
151586
151587
151588

151589
151590
151591
151592
151593
151594
151595
 /*   480 */  1819, 1860, 1779, 1859, 1863, 1823, 1849, 1865, 1734, 1867,
 /*   490 */  1868, 1869, 1870, 1871, 1872, 1874, 1875, 1877, 1876, 1878,
 /*   500 */  1764, 1881, 1882, 1780, 1873, 1879, 1765, 1883, 1880, 1884,
 /*   510 */  1885, 1886, 1820, 1835, 1825, 1887, 1840, 1828, 1888, 1889,
 /*   520 */  1891, 1892, 1897, 1898, 1893, 1894, 1883, 1902, 1903, 1905,
 /*   530 */  1906, 1904, 1909, 1911, 1923, 1913, 1914, 1915, 1916, 1918,
 /*   540 */  1919, 1917, 1804, 1803, 1805, 1806, 1818, 1924, 1931, 1947,

};
#define YY_REDUCE_COUNT (389)
#define YY_REDUCE_MIN   (-262)
#define YY_REDUCE_MAX   (1617)
static const short yy_reduce_ofst[] = {
 /*     0 */   490, -122,  545,  645,  650, -120, -189, -187, -184, -182,
 /*    10 */  -178, -176,   45,   30,  200, -251, -134,  390,  392,  521,







>







153301
153302
153303
153304
153305
153306
153307
153308
153309
153310
153311
153312
153313
153314
153315
 /*   480 */  1819, 1860, 1779, 1859, 1863, 1823, 1849, 1865, 1734, 1867,
 /*   490 */  1868, 1869, 1870, 1871, 1872, 1874, 1875, 1877, 1876, 1878,
 /*   500 */  1764, 1881, 1882, 1780, 1873, 1879, 1765, 1883, 1880, 1884,
 /*   510 */  1885, 1886, 1820, 1835, 1825, 1887, 1840, 1828, 1888, 1889,
 /*   520 */  1891, 1892, 1897, 1898, 1893, 1894, 1883, 1902, 1903, 1905,
 /*   530 */  1906, 1904, 1909, 1911, 1923, 1913, 1914, 1915, 1916, 1918,
 /*   540 */  1919, 1917, 1804, 1803, 1805, 1806, 1818, 1924, 1931, 1947,
 /*   550 */  1948,
};
#define YY_REDUCE_COUNT (389)
#define YY_REDUCE_MIN   (-262)
#define YY_REDUCE_MAX   (1617)
static const short yy_reduce_ofst[] = {
 /*     0 */   490, -122,  545,  645,  650, -120, -189, -187, -184, -182,
 /*    10 */  -178, -176,   45,   30,  200, -251, -134,  390,  392,  521,
151628
151629
151630
151631
151632
151633
151634
151635
151636
151637
151638
151639
151640
151641
151642
151643
151644
151645
151646
151647
151648
151649
151650
151651
151652
151653
151654
151655
151656
151657
151658
151659
151660
151661
151662
151663
151664
151665
151666
151667
151668
151669
151670
151671
151672
151673
151674
151675
151676
151677
151678
151679
151680
151681
151682
151683
151684
151685
151686
151687
151688
151689

151690
151691
151692
151693
151694
151695
151696
 /*   340 */  1547, 1450, 1543, 1477, 1482, 1551, 1505, 1508, 1512, 1509,
 /*   350 */  1515, 1518, 1533, 1552, 1573, 1466, 1468, 1549, 1550, 1555,
 /*   360 */  1554, 1510, 1583, 1511, 1556, 1559, 1561, 1565, 1588, 1592,
 /*   370 */  1601, 1602, 1607, 1608, 1609, 1498, 1557, 1558, 1610, 1600,
 /*   380 */  1603, 1611, 1612, 1613, 1596, 1597, 1614, 1615, 1617, 1616,
};
static const YYACTIONTYPE yy_default[] = {
 /*     0 */  1572, 1572, 1572, 1408, 1185, 1294, 1185, 1185, 1185, 1408,
 /*    10 */  1408, 1408, 1185, 1324, 1324, 1461, 1216, 1185, 1185, 1185,
 /*    20 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1407, 1185, 1185,
 /*    30 */  1185, 1185, 1491, 1491, 1185, 1185, 1185, 1185, 1185, 1185,
 /*    40 */  1185, 1185, 1185, 1333, 1185, 1185, 1185, 1185, 1185, 1185,
 /*    50 */  1409, 1410, 1185, 1185, 1185, 1460, 1462, 1425, 1343, 1342,
 /*    60 */  1341, 1340, 1443, 1311, 1338, 1331, 1335, 1403, 1404, 1402,
 /*    70 */  1406, 1410, 1409, 1185, 1334, 1374, 1388, 1373, 1185, 1185,
 /*    80 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*    90 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   100 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   110 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   120 */  1185, 1185, 1185, 1185, 1185, 1185, 1382, 1387, 1393, 1386,
 /*   130 */  1383, 1376, 1375, 1377, 1378, 1185, 1206, 1258, 1185, 1185,
 /*   140 */  1185, 1185, 1479, 1478, 1185, 1185, 1216, 1368, 1367, 1379,
 /*   150 */  1380, 1390, 1389, 1468, 1526, 1525, 1426, 1185, 1185, 1185,
 /*   160 */  1185, 1185, 1185, 1491, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   170 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   180 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1491, 1491,
 /*   190 */  1185, 1216, 1491, 1491, 1212, 1212, 1318, 1185, 1474, 1294,
 /*   200 */  1285, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   210 */  1185, 1185, 1185, 1185, 1185, 1465, 1463, 1185, 1185, 1185,
 /*   220 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   230 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   240 */  1185, 1185, 1185, 1185, 1185, 1290, 1185, 1185, 1185, 1185,
 /*   250 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1520, 1185, 1438,
 /*   260 */  1272, 1290, 1290, 1290, 1290, 1292, 1273, 1271, 1284, 1217,
 /*   270 */  1192, 1564, 1337, 1313, 1313, 1561, 1337, 1337, 1561, 1233,
 /*   280 */  1542, 1228, 1324, 1324, 1324, 1313, 1318, 1318, 1405, 1291,
 /*   290 */  1284, 1185, 1564, 1299, 1299, 1563, 1563, 1299, 1426, 1346,
 /*   300 */  1352, 1261, 1337, 1267, 1267, 1267, 1267, 1299, 1203, 1337,
 /*   310 */  1337, 1346, 1352, 1261, 1261, 1337, 1299, 1203, 1442, 1558,
 /*   320 */  1299, 1203, 1416, 1299, 1203, 1299, 1203, 1416, 1259, 1259,
 /*   330 */  1259, 1248, 1185, 1185, 1416, 1259, 1233, 1259, 1248, 1259,
 /*   340 */  1259, 1509, 1416, 1420, 1420, 1416, 1317, 1312, 1317, 1312,
 /*   350 */  1317, 1312, 1317, 1312, 1299, 1501, 1501, 1327, 1327, 1332,
 /*   360 */  1318, 1411, 1299, 1185, 1332, 1330, 1328, 1337, 1209, 1251,
 /*   370 */  1523, 1523, 1519, 1519, 1519, 1569, 1569, 1474, 1535, 1216,
 /*   380 */  1216, 1216, 1216, 1535, 1235, 1235, 1217, 1217, 1216, 1535,
 /*   390 */  1185, 1185, 1185, 1185, 1185, 1185, 1530, 1185, 1427, 1303,
 /*   400 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   410 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   420 */  1185, 1185, 1185, 1357, 1185, 1188, 1471, 1185, 1185, 1469,
 /*   430 */  1185, 1185, 1185, 1185, 1185, 1185, 1304, 1185, 1185, 1185,
 /*   440 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   450 */  1185, 1185, 1185, 1185, 1185, 1560, 1185, 1185, 1185, 1185,
 /*   460 */  1185, 1185, 1441, 1440, 1185, 1185, 1301, 1185, 1185, 1185,
 /*   470 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   480 */  1231, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   490 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   500 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1329, 1185, 1185,
 /*   510 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   520 */  1185, 1185, 1506, 1319, 1185, 1185, 1551, 1185, 1185, 1185,
 /*   530 */  1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185,
 /*   540 */  1185, 1546, 1275, 1359, 1185, 1358, 1362, 1185, 1197, 1185,

};
/********** End of lemon-generated parsing tables *****************************/

/* The next table maps tokens (terminal symbols) into fallback tokens.  
** If a construct like the following:
** 
**      %fallback ID X Y Z.







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







153348
153349
153350
153351
153352
153353
153354
153355
153356
153357
153358
153359
153360
153361
153362
153363
153364
153365
153366
153367
153368
153369
153370
153371
153372
153373
153374
153375
153376
153377
153378
153379
153380
153381
153382
153383
153384
153385
153386
153387
153388
153389
153390
153391
153392
153393
153394
153395
153396
153397
153398
153399
153400
153401
153402
153403
153404
153405
153406
153407
153408
153409
153410
153411
153412
153413
153414
153415
153416
153417
 /*   340 */  1547, 1450, 1543, 1477, 1482, 1551, 1505, 1508, 1512, 1509,
 /*   350 */  1515, 1518, 1533, 1552, 1573, 1466, 1468, 1549, 1550, 1555,
 /*   360 */  1554, 1510, 1583, 1511, 1556, 1559, 1561, 1565, 1588, 1592,
 /*   370 */  1601, 1602, 1607, 1608, 1609, 1498, 1557, 1558, 1610, 1600,
 /*   380 */  1603, 1611, 1612, 1613, 1596, 1597, 1614, 1615, 1617, 1616,
};
static const YYACTIONTYPE yy_default[] = {
 /*     0 */  1573, 1573, 1573, 1409, 1186, 1295, 1186, 1186, 1186, 1409,
 /*    10 */  1409, 1409, 1186, 1325, 1325, 1462, 1217, 1186, 1186, 1186,
 /*    20 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1408, 1186, 1186,
 /*    30 */  1186, 1186, 1492, 1492, 1186, 1186, 1186, 1186, 1186, 1186,
 /*    40 */  1186, 1186, 1186, 1334, 1186, 1186, 1186, 1186, 1186, 1186,
 /*    50 */  1410, 1411, 1186, 1186, 1186, 1461, 1463, 1426, 1344, 1343,
 /*    60 */  1342, 1341, 1444, 1312, 1339, 1332, 1336, 1404, 1405, 1403,
 /*    70 */  1407, 1411, 1410, 1186, 1335, 1375, 1389, 1374, 1186, 1186,
 /*    80 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*    90 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   100 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   110 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   120 */  1186, 1186, 1186, 1186, 1186, 1186, 1383, 1388, 1394, 1387,
 /*   130 */  1384, 1377, 1376, 1378, 1379, 1186, 1207, 1259, 1186, 1186,
 /*   140 */  1186, 1186, 1480, 1479, 1186, 1186, 1217, 1369, 1368, 1380,
 /*   150 */  1381, 1391, 1390, 1469, 1527, 1526, 1427, 1186, 1186, 1186,
 /*   160 */  1186, 1186, 1186, 1492, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   170 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   180 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1492, 1492,
 /*   190 */  1186, 1217, 1492, 1492, 1213, 1213, 1319, 1186, 1475, 1295,
 /*   200 */  1286, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   210 */  1186, 1186, 1186, 1186, 1186, 1466, 1464, 1186, 1186, 1186,
 /*   220 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   230 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   240 */  1186, 1186, 1186, 1186, 1186, 1291, 1186, 1186, 1186, 1186,
 /*   250 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1521, 1186, 1439,
 /*   260 */  1273, 1291, 1291, 1291, 1291, 1293, 1274, 1272, 1285, 1218,
 /*   270 */  1193, 1565, 1338, 1314, 1314, 1562, 1338, 1338, 1562, 1234,
 /*   280 */  1543, 1229, 1325, 1325, 1325, 1314, 1319, 1319, 1406, 1292,
 /*   290 */  1285, 1186, 1565, 1300, 1300, 1564, 1564, 1300, 1427, 1347,
 /*   300 */  1353, 1262, 1338, 1268, 1268, 1268, 1268, 1300, 1204, 1338,
 /*   310 */  1338, 1347, 1353, 1262, 1262, 1338, 1300, 1204, 1443, 1559,
 /*   320 */  1300, 1204, 1417, 1300, 1204, 1300, 1204, 1417, 1260, 1260,
 /*   330 */  1260, 1249, 1186, 1186, 1417, 1260, 1234, 1260, 1249, 1260,
 /*   340 */  1260, 1510, 1417, 1421, 1421, 1417, 1318, 1313, 1318, 1313,
 /*   350 */  1318, 1313, 1318, 1313, 1300, 1502, 1502, 1328, 1328, 1333,
 /*   360 */  1319, 1412, 1300, 1186, 1333, 1331, 1329, 1338, 1210, 1252,
 /*   370 */  1524, 1524, 1520, 1520, 1520, 1570, 1570, 1475, 1536, 1217,
 /*   380 */  1217, 1217, 1217, 1536, 1236, 1236, 1218, 1218, 1217, 1536,
 /*   390 */  1186, 1186, 1186, 1186, 1186, 1186, 1531, 1186, 1428, 1304,
 /*   400 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   410 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   420 */  1186, 1186, 1186, 1358, 1186, 1189, 1472, 1186, 1186, 1470,
 /*   430 */  1186, 1186, 1186, 1186, 1186, 1186, 1305, 1186, 1186, 1186,
 /*   440 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   450 */  1186, 1186, 1186, 1186, 1186, 1561, 1186, 1186, 1186, 1186,
 /*   460 */  1186, 1186, 1442, 1441, 1186, 1186, 1302, 1186, 1186, 1186,
 /*   470 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   480 */  1232, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   490 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   500 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1330, 1186, 1186,
 /*   510 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   520 */  1186, 1186, 1507, 1320, 1186, 1186, 1552, 1186, 1186, 1186,
 /*   530 */  1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
 /*   540 */  1186, 1547, 1276, 1360, 1186, 1359, 1363, 1186, 1198, 1186,
 /*   550 */  1186,
};
/********** End of lemon-generated parsing tables *****************************/

/* The next table maps tokens (terminal symbols) into fallback tokens.  
** If a construct like the following:
** 
**      %fallback ID X Y Z.
152617
152618
152619
152620
152621
152622
152623
152624
152625
152626
152627
152628
152629
152630
152631
 /* 323 */ "over_clause ::= OVER nm",
 /* 324 */ "filter_clause ::= FILTER LP WHERE expr RP",
 /* 325 */ "input ::= cmdlist",
 /* 326 */ "cmdlist ::= cmdlist ecmd",
 /* 327 */ "cmdlist ::= ecmd",
 /* 328 */ "ecmd ::= SEMI",
 /* 329 */ "ecmd ::= cmdx SEMI",
 /* 330 */ "ecmd ::= explain cmdx",
 /* 331 */ "trans_opt ::=",
 /* 332 */ "trans_opt ::= TRANSACTION",
 /* 333 */ "trans_opt ::= TRANSACTION nm",
 /* 334 */ "savepoint_opt ::= SAVEPOINT",
 /* 335 */ "savepoint_opt ::=",
 /* 336 */ "cmd ::= create_table create_table_args",
 /* 337 */ "columnlist ::= columnlist COMMA columnname carglist",







|







154338
154339
154340
154341
154342
154343
154344
154345
154346
154347
154348
154349
154350
154351
154352
 /* 323 */ "over_clause ::= OVER nm",
 /* 324 */ "filter_clause ::= FILTER LP WHERE expr RP",
 /* 325 */ "input ::= cmdlist",
 /* 326 */ "cmdlist ::= cmdlist ecmd",
 /* 327 */ "cmdlist ::= ecmd",
 /* 328 */ "ecmd ::= SEMI",
 /* 329 */ "ecmd ::= cmdx SEMI",
 /* 330 */ "ecmd ::= explain cmdx SEMI",
 /* 331 */ "trans_opt ::=",
 /* 332 */ "trans_opt ::= TRANSACTION",
 /* 333 */ "trans_opt ::= TRANSACTION nm",
 /* 334 */ "savepoint_opt ::= SAVEPOINT",
 /* 335 */ "savepoint_opt ::=",
 /* 336 */ "cmd ::= create_table create_table_args",
 /* 337 */ "columnlist ::= columnlist COMMA columnname carglist",
153509
153510
153511
153512
153513
153514
153515
153516
153517
153518
153519
153520
153521
153522
153523
   303,  /* (323) over_clause ::= OVER nm */
   302,  /* (324) filter_clause ::= FILTER LP WHERE expr RP */
   181,  /* (325) input ::= cmdlist */
   182,  /* (326) cmdlist ::= cmdlist ecmd */
   182,  /* (327) cmdlist ::= ecmd */
   183,  /* (328) ecmd ::= SEMI */
   183,  /* (329) ecmd ::= cmdx SEMI */
   183,  /* (330) ecmd ::= explain cmdx */
   188,  /* (331) trans_opt ::= */
   188,  /* (332) trans_opt ::= TRANSACTION */
   188,  /* (333) trans_opt ::= TRANSACTION nm */
   190,  /* (334) savepoint_opt ::= SAVEPOINT */
   190,  /* (335) savepoint_opt ::= */
   186,  /* (336) cmd ::= create_table create_table_args */
   197,  /* (337) columnlist ::= columnlist COMMA columnname carglist */







|







155230
155231
155232
155233
155234
155235
155236
155237
155238
155239
155240
155241
155242
155243
155244
   303,  /* (323) over_clause ::= OVER nm */
   302,  /* (324) filter_clause ::= FILTER LP WHERE expr RP */
   181,  /* (325) input ::= cmdlist */
   182,  /* (326) cmdlist ::= cmdlist ecmd */
   182,  /* (327) cmdlist ::= ecmd */
   183,  /* (328) ecmd ::= SEMI */
   183,  /* (329) ecmd ::= cmdx SEMI */
   183,  /* (330) ecmd ::= explain cmdx SEMI */
   188,  /* (331) trans_opt ::= */
   188,  /* (332) trans_opt ::= TRANSACTION */
   188,  /* (333) trans_opt ::= TRANSACTION nm */
   190,  /* (334) savepoint_opt ::= SAVEPOINT */
   190,  /* (335) savepoint_opt ::= */
   186,  /* (336) cmd ::= create_table create_table_args */
   197,  /* (337) columnlist ::= columnlist COMMA columnname carglist */
153899
153900
153901
153902
153903
153904
153905
153906
153907
153908
153909
153910
153911
153912
153913
   -2,  /* (323) over_clause ::= OVER nm */
   -5,  /* (324) filter_clause ::= FILTER LP WHERE expr RP */
   -1,  /* (325) input ::= cmdlist */
   -2,  /* (326) cmdlist ::= cmdlist ecmd */
   -1,  /* (327) cmdlist ::= ecmd */
   -1,  /* (328) ecmd ::= SEMI */
   -2,  /* (329) ecmd ::= cmdx SEMI */
   -2,  /* (330) ecmd ::= explain cmdx */
    0,  /* (331) trans_opt ::= */
   -1,  /* (332) trans_opt ::= TRANSACTION */
   -2,  /* (333) trans_opt ::= TRANSACTION nm */
   -1,  /* (334) savepoint_opt ::= SAVEPOINT */
    0,  /* (335) savepoint_opt ::= */
   -2,  /* (336) cmd ::= create_table create_table_args */
   -4,  /* (337) columnlist ::= columnlist COMMA columnname carglist */







|







155620
155621
155622
155623
155624
155625
155626
155627
155628
155629
155630
155631
155632
155633
155634
   -2,  /* (323) over_clause ::= OVER nm */
   -5,  /* (324) filter_clause ::= FILTER LP WHERE expr RP */
   -1,  /* (325) input ::= cmdlist */
   -2,  /* (326) cmdlist ::= cmdlist ecmd */
   -1,  /* (327) cmdlist ::= ecmd */
   -1,  /* (328) ecmd ::= SEMI */
   -2,  /* (329) ecmd ::= cmdx SEMI */
   -3,  /* (330) ecmd ::= explain cmdx SEMI */
    0,  /* (331) trans_opt ::= */
   -1,  /* (332) trans_opt ::= TRANSACTION */
   -2,  /* (333) trans_opt ::= TRANSACTION nm */
   -1,  /* (334) savepoint_opt ::= SAVEPOINT */
    0,  /* (335) savepoint_opt ::= */
   -2,  /* (336) cmd ::= create_table create_table_args */
   -4,  /* (337) columnlist ::= columnlist COMMA columnname carglist */
153987
153988
153989
153990
153991
153992
153993
153994
153995
153996


153997
153998
153999

154000
154001
154002
154003
154004
154005
154006
  (void)yyLookahead;
  (void)yyLookaheadToken;
  yymsp = yypParser->yytos;
#ifndef NDEBUG
  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
    yysize = yyRuleInfoNRhs[yyruleno];
    if( yysize ){
      fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
        yyTracePrompt,
        yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno);


    }else{
      fprintf(yyTraceFILE, "%sReduce %d [%s].\n",
        yyTracePrompt, yyruleno, yyRuleName[yyruleno]);

    }
  }
#endif /* NDEBUG */

  /* Check that the stack is large enough to grow by a single entry
  ** if the RHS of the rule is empty.  This ensures that there is room
  ** enough on the stack to push the LHS value */







|

|
>
>

|
|
>







155708
155709
155710
155711
155712
155713
155714
155715
155716
155717
155718
155719
155720
155721
155722
155723
155724
155725
155726
155727
155728
155729
155730
  (void)yyLookahead;
  (void)yyLookaheadToken;
  yymsp = yypParser->yytos;
#ifndef NDEBUG
  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
    yysize = yyRuleInfoNRhs[yyruleno];
    if( yysize ){
      fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
        yyTracePrompt,
        yyruleno, yyRuleName[yyruleno],
        yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
        yymsp[yysize].stateno);
    }else{
      fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
        yyTracePrompt, yyruleno, yyRuleName[yyruleno],
        yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
    }
  }
#endif /* NDEBUG */

  /* Check that the stack is large enough to grow by a single entry
  ** if the RHS of the rule is empty.  This ensures that there is room
  ** enough on the stack to push the LHS value */
154931
154932
154933
154934
154935
154936
154937







154938
154939
154940
154941
154942
154943
154944
      **      expr1 NOT IN ()
      **
      ** simplify to constants 0 (false) and 1 (true), respectively,
      ** regardless of the value of expr1.
      */
      sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy202);
      yymsp[-4].minor.yy202 = sqlite3Expr(pParse->db, TK_INTEGER, yymsp[-3].minor.yy192 ? "1" : "0");







    }else{
      yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy202, 0);
      if( yymsp[-4].minor.yy202 ){
        yymsp[-4].minor.yy202->x.pList = yymsp[-1].minor.yy242;
        sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy202);
      }else{
        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy242);







>
>
>
>
>
>
>







156655
156656
156657
156658
156659
156660
156661
156662
156663
156664
156665
156666
156667
156668
156669
156670
156671
156672
156673
156674
156675
      **      expr1 NOT IN ()
      **
      ** simplify to constants 0 (false) and 1 (true), respectively,
      ** regardless of the value of expr1.
      */
      sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy202);
      yymsp[-4].minor.yy202 = sqlite3Expr(pParse->db, TK_INTEGER, yymsp[-3].minor.yy192 ? "1" : "0");
    }else if( yymsp[-1].minor.yy242->nExpr==1 && sqlite3ExprIsConstant(yymsp[-1].minor.yy242->a[0].pExpr) ){
      Expr *pRHS = yymsp[-1].minor.yy242->a[0].pExpr;
      yymsp[-1].minor.yy242->a[0].pExpr = 0;
      sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy242);
      pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
      yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy202, pRHS);
      if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
    }else{
      yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy202, 0);
      if( yymsp[-4].minor.yy202 ){
        yymsp[-4].minor.yy202->x.pList = yymsp[-1].minor.yy242;
        sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy202);
      }else{
        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy242);
155403
155404
155405
155406
155407
155408
155409
155410
155411
155412
155413
155414
155415
155416
155417
        break;
      default:
      /* (325) input ::= cmdlist */ yytestcase(yyruleno==325);
      /* (326) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==326);
      /* (327) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=327);
      /* (328) ecmd ::= SEMI */ yytestcase(yyruleno==328);
      /* (329) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==329);
      /* (330) ecmd ::= explain cmdx */ yytestcase(yyruleno==330);
      /* (331) trans_opt ::= */ yytestcase(yyruleno==331);
      /* (332) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==332);
      /* (333) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==333);
      /* (334) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==334);
      /* (335) savepoint_opt ::= */ yytestcase(yyruleno==335);
      /* (336) cmd ::= create_table create_table_args */ yytestcase(yyruleno==336);
      /* (337) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==337);







|







157134
157135
157136
157137
157138
157139
157140
157141
157142
157143
157144
157145
157146
157147
157148
        break;
      default:
      /* (325) input ::= cmdlist */ yytestcase(yyruleno==325);
      /* (326) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==326);
      /* (327) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=327);
      /* (328) ecmd ::= SEMI */ yytestcase(yyruleno==328);
      /* (329) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==329);
      /* (330) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=330);
      /* (331) trans_opt ::= */ yytestcase(yyruleno==331);
      /* (332) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==332);
      /* (333) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==333);
      /* (334) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==334);
      /* (335) savepoint_opt ::= */ yytestcase(yyruleno==335);
      /* (336) cmd ::= create_table create_table_args */ yytestcase(yyruleno==336);
      /* (337) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==337);
156202
156203
156204
156205
156206
156207
156208
156209
156210
156211



156212
156213
156214



156215
156216
156217
156218
156219
156220
156221
static int keywordCode(const char *z, int n, int *pType){
  int i, j;
  const char *zKW;
  if( n>=2 ){
    i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127;
    for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
      if( aKWLen[i]!=n ) continue;
      j = 0;
      zKW = &zKWText[aKWOffset[i]];
#ifdef SQLITE_ASCII



      while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
#endif
#ifdef SQLITE_EBCDIC



      while( j<n && toupper(z[j])==zKW[j] ){ j++; }
#endif
      if( j<n ) continue;
      testcase( i==0 ); /* REINDEX */
      testcase( i==1 ); /* INDEXED */
      testcase( i==2 ); /* INDEX */
      testcase( i==3 ); /* DESC */







<


>
>
>



>
>
>







157933
157934
157935
157936
157937
157938
157939

157940
157941
157942
157943
157944
157945
157946
157947
157948
157949
157950
157951
157952
157953
157954
157955
157956
157957
static int keywordCode(const char *z, int n, int *pType){
  int i, j;
  const char *zKW;
  if( n>=2 ){
    i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127;
    for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
      if( aKWLen[i]!=n ) continue;

      zKW = &zKWText[aKWOffset[i]];
#ifdef SQLITE_ASCII
      if( (z[0]&~0x20)!=zKW[0] ) continue;
      if( (z[1]&~0x20)!=zKW[1] ) continue;
      j = 2;
      while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
#endif
#ifdef SQLITE_EBCDIC
      if( toupper(z[0])!=zKW[0] ) continue;
      if( toupper(z[1])!=zKW[1] ) continue;
      j = 2;
      while( j<n && toupper(z[j])==zKW[j] ){ j++; }
#endif
      if( j<n ) continue;
      testcase( i==0 ); /* REINDEX */
      testcase( i==1 ); /* INDEXED */
      testcase( i==2 ); /* INDEX */
      testcase( i==3 ); /* DESC */
156805
156806
156807
156808
156809
156810
156811
156812
156813
156814
156815
156816
156817
156818
156819
  yyParser sEngine;    /* Space to hold the Lemon-generated Parser object */
#endif
  VVA_ONLY( u8 startedWithOom = db->mallocFailed );

  assert( zSql!=0 );
  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
  if( db->nVdbeActive==0 ){
    db->u1.isInterrupted = 0;
  }
  pParse->rc = SQLITE_OK;
  pParse->zTail = zSql;
  assert( pzErrMsg!=0 );
#ifdef SQLITE_DEBUG
  if( db->flags & SQLITE_ParserTrace ){
    printf("parser: [[[%s]]]\n", zSql);







|







158541
158542
158543
158544
158545
158546
158547
158548
158549
158550
158551
158552
158553
158554
158555
  yyParser sEngine;    /* Space to hold the Lemon-generated Parser object */
#endif
  VVA_ONLY( u8 startedWithOom = db->mallocFailed );

  assert( zSql!=0 );
  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
  if( db->nVdbeActive==0 ){
    AtomicStore(&db->u1.isInterrupted, 0);
  }
  pParse->rc = SQLITE_OK;
  pParse->zTail = zSql;
  assert( pzErrMsg!=0 );
#ifdef SQLITE_DEBUG
  if( db->flags & SQLITE_ParserTrace ){
    printf("parser: [[[%s]]]\n", zSql);
156850
156851
156852
156853
156854
156855
156856
156857
156858
156859
156860
156861
156862
156863
156864
      assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
           || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW 
      );
#else
    if( tokenType>=TK_SPACE ){
      assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
#endif /* SQLITE_OMIT_WINDOWFUNC */
      if( db->u1.isInterrupted ){
        pParse->rc = SQLITE_INTERRUPT;
        break;
      }
      if( tokenType==TK_SPACE ){
        zSql += n;
        continue;
      }







|







158586
158587
158588
158589
158590
158591
158592
158593
158594
158595
158596
158597
158598
158599
158600
      assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
           || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW 
      );
#else
    if( tokenType>=TK_SPACE ){
      assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
#endif /* SQLITE_OMIT_WINDOWFUNC */
      if( AtomicLoad(&db->u1.isInterrupted) ){
        pParse->rc = SQLITE_INTERRUPT;
        break;
      }
      if( tokenType==TK_SPACE ){
        zSql += n;
        continue;
      }
157653
157654
157655
157656
157657
157658
157659
157660



157661
157662
157663
157664
157665
157666
157667
  assert( SQLITE_PTRSIZE==sizeof(char*) );

  /* If SQLite is already completely initialized, then this call
  ** to sqlite3_initialize() should be a no-op.  But the initialization
  ** must be complete.  So isInit must not be set until the very end
  ** of this routine.
  */
  if( sqlite3GlobalConfig.isInit ) return SQLITE_OK;




  /* Make sure the mutex subsystem is initialized.  If unable to 
  ** initialize the mutex subsystem, return early with the error.
  ** If the system is so sick that we are unable to allocate a mutex,
  ** there is not much SQLite is going to be able to do.
  **
  ** The mutex subsystem must take care of serializing its own







|
>
>
>







159389
159390
159391
159392
159393
159394
159395
159396
159397
159398
159399
159400
159401
159402
159403
159404
159405
159406
  assert( SQLITE_PTRSIZE==sizeof(char*) );

  /* If SQLite is already completely initialized, then this call
  ** to sqlite3_initialize() should be a no-op.  But the initialization
  ** must be complete.  So isInit must not be set until the very end
  ** of this routine.
  */
  if( sqlite3GlobalConfig.isInit ){
    sqlite3MemoryBarrier();
    return SQLITE_OK;
  }

  /* Make sure the mutex subsystem is initialized.  If unable to 
  ** initialize the mutex subsystem, return early with the error.
  ** If the system is so sick that we are unable to allocate a mutex,
  ** there is not much SQLite is going to be able to do.
  **
  ** The mutex subsystem must take care of serializing its own
158175
158176
158177
158178
158179
158180
158181



158182
158183
158184
158185
158186
158187
158188
** space for the lookaside memory is obtained from sqlite3_malloc().
** If pStart is not NULL then it is sz*cnt bytes of memory to use for
** the lookaside memory.
*/
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
#ifndef SQLITE_OMIT_LOOKASIDE
  void *pStart;



  
  if( sqlite3LookasideUsed(db,0)>0 ){
    return SQLITE_BUSY;
  }
  /* Free any existing lookaside buffer for this handle before
  ** allocating a new one so we don't have to have space for 
  ** both at the same time.







>
>
>







159914
159915
159916
159917
159918
159919
159920
159921
159922
159923
159924
159925
159926
159927
159928
159929
159930
** space for the lookaside memory is obtained from sqlite3_malloc().
** If pStart is not NULL then it is sz*cnt bytes of memory to use for
** the lookaside memory.
*/
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
#ifndef SQLITE_OMIT_LOOKASIDE
  void *pStart;
  sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;
  int nBig;   /* Number of full-size slots */
  int nSm;    /* Number smaller LOOKASIDE_SMALL-byte slots */
  
  if( sqlite3LookasideUsed(db,0)>0 ){
    return SQLITE_BUSY;
  }
  /* Free any existing lookaside buffer for this handle before
  ** allocating a new one so we don't have to have space for 
  ** both at the same time.
158197
158198
158199
158200
158201
158202
158203
158204
158205
158206
158207
158208















158209
158210
158211
158212
158213
158214
158215
158216
158217
158218
158219
158220
158221
158222
158223
158224
158225











158226
158227
158228

158229
158230





158231
158232
158233
158234
158235
158236

158237
158238
158239
158240
158241
158242
158243
  if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0;
  if( cnt<0 ) cnt = 0;
  if( sz==0 || cnt==0 ){
    sz = 0;
    pStart = 0;
  }else if( pBuf==0 ){
    sqlite3BeginBenignMalloc();
    pStart = sqlite3Malloc( sz*(sqlite3_int64)cnt );  /* IMP: R-61949-35727 */
    sqlite3EndBenignMalloc();
    if( pStart ) cnt = sqlite3MallocSize(pStart)/sz;
  }else{
    pStart = pBuf;















  }
  db->lookaside.pStart = pStart;
  db->lookaside.pInit = 0;
  db->lookaside.pFree = 0;
  db->lookaside.sz = (u16)sz;
  db->lookaside.szTrue = (u16)sz;
  if( pStart ){
    int i;
    LookasideSlot *p;
    assert( sz > (int)sizeof(LookasideSlot*) );
    db->lookaside.nSlot = cnt;
    p = (LookasideSlot*)pStart;
    for(i=cnt-1; i>=0; i--){
      p->pNext = db->lookaside.pInit;
      db->lookaside.pInit = p;
      p = (LookasideSlot*)&((u8*)p)[sz];
    }











    db->lookaside.pEnd = p;
    db->lookaside.bDisable = 0;
    db->lookaside.bMalloced = pBuf==0 ?1:0;

  }else{
    db->lookaside.pStart = db;





    db->lookaside.pEnd = db;
    db->lookaside.bDisable = 1;
    db->lookaside.sz = 0;
    db->lookaside.bMalloced = 0;
    db->lookaside.nSlot = 0;
  }

#endif /* SQLITE_OMIT_LOOKASIDE */
  return SQLITE_OK;
}

/*
** Return the mutex associated with a database connection.
*/







|

|


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










<

|




>
>
>
>
>
>
>
>
>
>
>



>


>
>
>
>
>






>







159939
159940
159941
159942
159943
159944
159945
159946
159947
159948
159949
159950
159951
159952
159953
159954
159955
159956
159957
159958
159959
159960
159961
159962
159963
159964
159965
159966
159967
159968
159969
159970
159971
159972
159973
159974
159975

159976
159977
159978
159979
159980
159981
159982
159983
159984
159985
159986
159987
159988
159989
159990
159991
159992
159993
159994
159995
159996
159997
159998
159999
160000
160001
160002
160003
160004
160005
160006
160007
160008
160009
160010
160011
160012
160013
160014
160015
160016
160017
  if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0;
  if( cnt<0 ) cnt = 0;
  if( sz==0 || cnt==0 ){
    sz = 0;
    pStart = 0;
  }else if( pBuf==0 ){
    sqlite3BeginBenignMalloc();
    pStart = sqlite3Malloc( szAlloc );  /* IMP: R-61949-35727 */
    sqlite3EndBenignMalloc();
    if( pStart ) szAlloc = sqlite3MallocSize(pStart);
  }else{
    pStart = pBuf;
  }
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
  if( sz>=LOOKASIDE_SMALL*3 ){
    nBig = szAlloc/(3*LOOKASIDE_SMALL+sz);
    nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
  }else if( sz>=LOOKASIDE_SMALL*2 ){
    nBig = szAlloc/(LOOKASIDE_SMALL+sz);
    nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
  }else
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
  if( sz>0 ){
    nBig = szAlloc/sz;
    nSm = 0;
  }else{
    nBig = nSm = 0;
  }
  db->lookaside.pStart = pStart;
  db->lookaside.pInit = 0;
  db->lookaside.pFree = 0;
  db->lookaside.sz = (u16)sz;
  db->lookaside.szTrue = (u16)sz;
  if( pStart ){
    int i;
    LookasideSlot *p;
    assert( sz > (int)sizeof(LookasideSlot*) );

    p = (LookasideSlot*)pStart;
    for(i=0; i<nBig; i++){
      p->pNext = db->lookaside.pInit;
      db->lookaside.pInit = p;
      p = (LookasideSlot*)&((u8*)p)[sz];
    }
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
    db->lookaside.pSmallInit = 0;
    db->lookaside.pSmallFree = 0;
    db->lookaside.pMiddle = p;
    for(i=0; i<nSm; i++){
      p->pNext = db->lookaside.pSmallInit;
      db->lookaside.pSmallInit = p;
      p = (LookasideSlot*)&((u8*)p)[LOOKASIDE_SMALL];
    }
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
    assert( ((uptr)p)<=szAlloc + (uptr)pStart );
    db->lookaside.pEnd = p;
    db->lookaside.bDisable = 0;
    db->lookaside.bMalloced = pBuf==0 ?1:0;
    db->lookaside.nSlot = nBig+nSm;
  }else{
    db->lookaside.pStart = db;
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
    db->lookaside.pSmallInit = 0;
    db->lookaside.pSmallFree = 0;
    db->lookaside.pMiddle = db;
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
    db->lookaside.pEnd = db;
    db->lookaside.bDisable = 1;
    db->lookaside.sz = 0;
    db->lookaside.bMalloced = 0;
    db->lookaside.nSlot = 0;
  }
  assert( sqlite3LookasideUsed(db,0)==0 );
#endif /* SQLITE_OMIT_LOOKASIDE */
  return SQLITE_OK;
}

/*
** Return the mutex associated with a database connection.
*/
158344
158345
158346
158347
158348
158349
158350

158351
158352
158353
158354
158355
158356
158357
        { SQLITE_DBCONFIG_DEFENSIVE,             SQLITE_Defensive      },
        { SQLITE_DBCONFIG_WRITABLE_SCHEMA,       SQLITE_WriteSchema|
                                                 SQLITE_NoSchemaError  },
        { SQLITE_DBCONFIG_LEGACY_ALTER_TABLE,    SQLITE_LegacyAlter    },
        { SQLITE_DBCONFIG_DQS_DDL,               SQLITE_DqsDDL         },
        { SQLITE_DBCONFIG_DQS_DML,               SQLITE_DqsDML         },
        { SQLITE_DBCONFIG_LEGACY_FILE_FORMAT,    SQLITE_LegacyFileFmt  },

      };
      unsigned int i;
      rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
      for(i=0; i<ArraySize(aFlagOp); i++){
        if( aFlagOp[i].op==op ){
          int onoff = va_arg(ap, int);
          int *pRes = va_arg(ap, int*);







>







160118
160119
160120
160121
160122
160123
160124
160125
160126
160127
160128
160129
160130
160131
160132
        { SQLITE_DBCONFIG_DEFENSIVE,             SQLITE_Defensive      },
        { SQLITE_DBCONFIG_WRITABLE_SCHEMA,       SQLITE_WriteSchema|
                                                 SQLITE_NoSchemaError  },
        { SQLITE_DBCONFIG_LEGACY_ALTER_TABLE,    SQLITE_LegacyAlter    },
        { SQLITE_DBCONFIG_DQS_DDL,               SQLITE_DqsDDL         },
        { SQLITE_DBCONFIG_DQS_DML,               SQLITE_DqsDML         },
        { SQLITE_DBCONFIG_LEGACY_FILE_FORMAT,    SQLITE_LegacyFileFmt  },
        { SQLITE_DBCONFIG_TRUSTED_SCHEMA,        SQLITE_TrustedSchema  },
      };
      unsigned int i;
      rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
      for(i=0; i<ArraySize(aFlagOp); i++){
        if( aFlagOp[i].op==op ){
          int onoff = va_arg(ap, int);
          int *pRes = va_arg(ap, int*);
159022
159023
159024
159025
159026
159027
159028











159029
159030
159031

159032
159033
159034
159035
159036
159037
159038
  sqlite3 *db = (sqlite3 *)ptr;
  int tmout = db->busyTimeout;
  int delay, prior;

#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
    if( count ){











      tmout = 0;
      sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
      return 0;

    }else{
      return 1;
    }
  }
#else
  UNUSED_PARAMETER(pFile);
#endif







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







160797
160798
160799
160800
160801
160802
160803
160804
160805
160806
160807
160808
160809
160810
160811
160812
160813
160814
160815
160816
160817
160818
160819
160820
160821
160822
160823
160824
160825
  sqlite3 *db = (sqlite3 *)ptr;
  int tmout = db->busyTimeout;
  int delay, prior;

#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
    if( count ){
      /* If this is the second or later invocation of the busy-handler,
      ** but tmout==0, then code in wal.c must have disabled the blocking
      ** lock before the SQLITE_BUSY error was hit. In this case, no delay
      ** occurred while waiting for the lock, so fall through to the xSleep()
      ** code below to delay a while before retrying the lock.  
      **
      ** Alternatively, if tmout!=0, then SQLite has already waited 
      ** sqlite3.busyTimeout ms for a lock. In this case, return 0 to 
      ** indicate that the lock should not be retried and the SQLITE_BUSY 
      ** error returned to the application.  */
      if( tmout ){
        tmout = 0;
        sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
        return 0;
      }
    }else{
      return 1;
    }
  }
#else
  UNUSED_PARAMETER(pFile);
#endif
159174
159175
159176
159177
159178
159179
159180
159181
159182
159183
159184
159185
159186
159187
159188
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
    (void)SQLITE_MISUSE_BKPT;
    return;
  }
#endif
  db->u1.isInterrupted = 1;
}


/*
** This function is exactly the same as sqlite3_create_function(), except
** that it is designed to be called by internal code. The difference is
** that if a malloc() fails in sqlite3_create_function(), an error code







|







160961
160962
160963
160964
160965
160966
160967
160968
160969
160970
160971
160972
160973
160974
160975
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
    (void)SQLITE_MISUSE_BKPT;
    return;
  }
#endif
  AtomicStore(&db->u1.isInterrupted, 1);
}


/*
** This function is exactly the same as sqlite3_create_function(), except
** that it is designed to be called by internal code. The difference is
** that if a malloc() fails in sqlite3_create_function(), an error code
159215
159216
159217
159218
159219
159220
159221
159222

159223






159224
159225
159226
159227
159228
159229
159230
159231
159232
159233
159234
159235
159236
159237

159238
159239
159240

159241
159242
159243
159244
159245
159246
159247
159248
   || (255<(nName = sqlite3Strlen30( zFunctionName)))
  ){
    return SQLITE_MISUSE_BKPT;
  }

  assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
  assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
  extraFlags = enc &  (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|SQLITE_SUBTYPE);

  enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);






  
#ifndef SQLITE_OMIT_UTF16
  /* If SQLITE_UTF16 is specified as the encoding type, transform this
  ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
  ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
  **
  ** If SQLITE_ANY is specified, add three versions of the function
  ** to the hash table.
  */
  if( enc==SQLITE_UTF16 ){
    enc = SQLITE_UTF16NATIVE;
  }else if( enc==SQLITE_ANY ){
    int rc;
    rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,

         pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
    if( rc==SQLITE_OK ){
      rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,

          pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
    }
    if( rc!=SQLITE_OK ){
      return rc;
    }
    enc = SQLITE_UTF16BE;
  }
#else







|
>

>
>
>
>
>
>













|
>


|
>
|







161002
161003
161004
161005
161006
161007
161008
161009
161010
161011
161012
161013
161014
161015
161016
161017
161018
161019
161020
161021
161022
161023
161024
161025
161026
161027
161028
161029
161030
161031
161032
161033
161034
161035
161036
161037
161038
161039
161040
161041
161042
161043
161044
   || (255<(nName = sqlite3Strlen30( zFunctionName)))
  ){
    return SQLITE_MISUSE_BKPT;
  }

  assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
  assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
  extraFlags = enc &  (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
                       SQLITE_SUBTYPE|SQLITE_INNOCUOUS);
  enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);

  /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE.  But
  ** the meaning is inverted.  So flip the bit. */
  assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
  extraFlags ^= SQLITE_FUNC_UNSAFE;

  
#ifndef SQLITE_OMIT_UTF16
  /* If SQLITE_UTF16 is specified as the encoding type, transform this
  ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
  ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
  **
  ** If SQLITE_ANY is specified, add three versions of the function
  ** to the hash table.
  */
  if( enc==SQLITE_UTF16 ){
    enc = SQLITE_UTF16NATIVE;
  }else if( enc==SQLITE_ANY ){
    int rc;
    rc = sqlite3CreateFunc(db, zFunctionName, nArg,
         (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE,
         pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
    if( rc==SQLITE_OK ){
      rc = sqlite3CreateFunc(db, zFunctionName, nArg,
           (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE,
           pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
    }
    if( rc!=SQLITE_OK ){
      return rc;
    }
    enc = SQLITE_UTF16BE;
  }
#else
159787
159788
159789
159790
159791
159792
159793
159794
159795
159796
159797
159798
159799
159800
159801
    sqlite3Error(db, rc);
  }
  rc = sqlite3ApiExit(db, rc);

  /* If there are no active statements, clear the interrupt flag at this
  ** point.  */
  if( db->nVdbeActive==0 ){
    db->u1.isInterrupted = 0;
  }

  sqlite3_mutex_leave(db->mutex);
  return rc;
#endif
}








|







161583
161584
161585
161586
161587
161588
161589
161590
161591
161592
161593
161594
161595
161596
161597
    sqlite3Error(db, rc);
  }
  rc = sqlite3ApiExit(db, rc);

  /* If there are no active statements, clear the interrupt flag at this
  ** point.  */
  if( db->nVdbeActive==0 ){
    AtomicStore(&db->u1.isInterrupted, 0);
  }

  sqlite3_mutex_leave(db->mutex);
  return rc;
#endif
}

160197
160198
160199
160200
160201
160202
160203
160204


160205
160206
160207
160208
160209
160210
160211
160212
160213
** itself. When this function is called the *pFlags variable should contain
** the default flags to open the database handle with. The value stored in
** *pFlags may be updated before returning if the URI filename contains 
** "cache=xxx" or "mode=xxx" query parameters.
**
** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to
** the VFS that should be used to open the database file. *pzFile is set to
** point to a buffer containing the name of the file to open. It is the 


** responsibility of the caller to eventually call sqlite3_free() to release
** this buffer.
**
** If an error occurs, then an SQLite error code is returned and *pzErrMsg
** may be set to point to a buffer containing an English language error 
** message. It is the responsibility of the caller to eventually release
** this buffer by calling sqlite3_free().
*/
SQLITE_PRIVATE int sqlite3ParseUri(







|
>
>
|
|







161993
161994
161995
161996
161997
161998
161999
162000
162001
162002
162003
162004
162005
162006
162007
162008
162009
162010
162011
** itself. When this function is called the *pFlags variable should contain
** the default flags to open the database handle with. The value stored in
** *pFlags may be updated before returning if the URI filename contains 
** "cache=xxx" or "mode=xxx" query parameters.
**
** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to
** the VFS that should be used to open the database file. *pzFile is set to
** point to a buffer containing the name of the file to open.  The value
** stored in *pzFile is a database name acceptable to sqlite3_uri_parameter()
** and is in the same format as names created using sqlite3_create_filename().
** The caller must invoke sqlite3_free_filename() (not sqlite3_free()!) on
** the value returned in *pzFile to avoid a memory leak.
**
** If an error occurs, then an SQLite error code is returned and *pzErrMsg
** may be set to point to a buffer containing an English language error 
** message. It is the responsibility of the caller to eventually release
** this buffer by calling sqlite3_free().
*/
SQLITE_PRIVATE int sqlite3ParseUri(
160231
160232
160233
160234
160235
160236
160237
160238
160239
160240
160241
160242
160243
160244
160245
160246



160247
160248
160249
160250
160251
160252
160253
            || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
   && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
  ){
    char *zOpt;
    int eState;                   /* Parser state when parsing URI */
    int iIn;                      /* Input character index */
    int iOut = 0;                 /* Output character index */
    u64 nByte = nUri+2;           /* Bytes of space to allocate */

    /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen 
    ** method that there may be extra parameters following the file-name.  */
    flags |= SQLITE_OPEN_URI;

    for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
    zFile = sqlite3_malloc64(nByte);
    if( !zFile ) return SQLITE_NOMEM_BKPT;




    iIn = 5;
#ifdef SQLITE_ALLOW_URI_AUTHORITY
    if( strncmp(zUri+5, "///", 3)==0 ){
      iIn = 7;
      /* The following condition causes URIs with five leading / characters
      ** like file://///host/path to be converted into UNCs like //host/path.







|








>
>
>







162029
162030
162031
162032
162033
162034
162035
162036
162037
162038
162039
162040
162041
162042
162043
162044
162045
162046
162047
162048
162049
162050
162051
162052
162053
162054
            || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
   && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
  ){
    char *zOpt;
    int eState;                   /* Parser state when parsing URI */
    int iIn;                      /* Input character index */
    int iOut = 0;                 /* Output character index */
    u64 nByte = nUri+8;           /* Bytes of space to allocate */

    /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen 
    ** method that there may be extra parameters following the file-name.  */
    flags |= SQLITE_OPEN_URI;

    for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
    zFile = sqlite3_malloc64(nByte);
    if( !zFile ) return SQLITE_NOMEM_BKPT;

    memset(zFile, 0, 4);  /* 4-byte of 0x00 is the start of DB name marker */
    zFile += 4;

    iIn = 5;
#ifdef SQLITE_ALLOW_URI_AUTHORITY
    if( strncmp(zUri+5, "///", 3)==0 ){
      iIn = 7;
      /* The following condition causes URIs with five leading / characters
      ** like file://///host/path to be converted into UNCs like //host/path.
160330
160331
160332
160333
160334
160335
160336
160337
160338
160339
160340
160341
160342
160343
160344
160345
      }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){
        c = 0;
        eState = 1;
      }
      zFile[iOut++] = c;
    }
    if( eState==1 ) zFile[iOut++] = '\0';
    zFile[iOut++] = '\0';
    zFile[iOut++] = '\0';

    /* Check if there were any options specified that should be interpreted 
    ** here. Options that are interpreted here include "vfs" and those that
    ** correspond to flags that may be passed to the sqlite3_open_v2()
    ** method. */
    zOpt = &zFile[sqlite3Strlen30(zFile)+1];
    while( zOpt[0] ){







|
<







162131
162132
162133
162134
162135
162136
162137
162138

162139
162140
162141
162142
162143
162144
162145
      }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){
        c = 0;
        eState = 1;
      }
      zFile[iOut++] = c;
    }
    if( eState==1 ) zFile[iOut++] = '\0';
    memset(zFile+iOut, 0, 4); /* end-of-options + empty journal filenames */


    /* Check if there were any options specified that should be interpreted 
    ** here. Options that are interpreted here include "vfs" and those that
    ** correspond to flags that may be passed to the sqlite3_open_v2()
    ** method. */
    zOpt = &zFile[sqlite3Strlen30(zFile)+1];
    while( zOpt[0] ){
160411
160412
160413
160414
160415
160416
160417
160418
160419


160420
160421
160422
160423
160424
160425
160426
160427
160428
160429
160430
160431
160432
160433
160434
160435
160436
160437
160438
160439
160440
160441
160442
160443
160444
160445
160446
160447
160448
160449
160450
160451
160452
160453
160454
160455
160456
160457
160458
160459
160460
160461

160462
160463
160464
160465
160466
160467
160468
160469
160470
160471
160472
160473
160474
160475
160476
160477
160478
160479
160480
160481
160482
        }
      }

      zOpt = &zVal[nVal+1];
    }

  }else{
    zFile = sqlite3_malloc64(nUri+2);
    if( !zFile ) return SQLITE_NOMEM_BKPT;


    if( nUri ){
      memcpy(zFile, zUri, nUri);
    }
    zFile[nUri] = '\0';
    zFile[nUri+1] = '\0';
    flags &= ~SQLITE_OPEN_URI;
  }

  *ppVfs = sqlite3_vfs_find(zVfs);
  if( *ppVfs==0 ){
    *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs);
    rc = SQLITE_ERROR;
  }
 parse_uri_out:
  if( rc!=SQLITE_OK ){
    sqlite3_free(zFile);
    zFile = 0;
  }
  *pFlags = flags;
  *pzFile = zFile;
  return rc;
}

#if defined(SQLITE_HAS_CODEC)
/*
** Process URI filename query parameters relevant to the SQLite Encryption
** Extension.  Return true if any of the relevant query parameters are
** seen and return false if not.
*/
SQLITE_PRIVATE int sqlite3CodecQueryParameters(
  sqlite3 *db,           /* Database connection */
  const char *zDb,       /* Which schema is being created/attached */
  const char *zUri       /* URI filename */
){
  const char *zKey;
  if( (zKey = sqlite3_uri_parameter(zUri, "hexkey"))!=0 && zKey[0] ){
    u8 iByte;
    int i;
    char zDecoded[40];
    for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
      iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
      if( (i&1)!=0 ) zDecoded[i/2] = iByte;

    }
    sqlite3_key_v2(db, zDb, zDecoded, i/2);
    return 1;
  }else if( (zKey = sqlite3_uri_parameter(zUri, "key"))!=0 ){
    sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey));
    return 1;
  }else if( (zKey = sqlite3_uri_parameter(zUri, "textkey"))!=0 ){
    sqlite3_key_v2(db, zDb, zKey, -1);
    return 1;
  }else{
    return 0;
  }
}
#endif


/*
** This routine does the work of opening a database on behalf of
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"  
** is UTF-8 encoded.
*/







|

>
>



|
<










|







<

|
|
<

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







162211
162212
162213
162214
162215
162216
162217
162218
162219
162220
162221
162222
162223
162224
162225

162226
162227
162228
162229
162230
162231
162232
162233
162234
162235
162236
162237
162238
162239
162240
162241
162242
162243

162244
162245
162246

162247
162248
162249

162250




162251


162252
162253
162254
162255









162256
162257
162258

162259
162260
162261
162262
162263
162264
162265
        }
      }

      zOpt = &zVal[nVal+1];
    }

  }else{
    zFile = sqlite3_malloc64(nUri+8);
    if( !zFile ) return SQLITE_NOMEM_BKPT;
    memset(zFile, 0, 4);
    zFile += 4;
    if( nUri ){
      memcpy(zFile, zUri, nUri);
    }
    memset(zFile+nUri, 0, 4);

    flags &= ~SQLITE_OPEN_URI;
  }

  *ppVfs = sqlite3_vfs_find(zVfs);
  if( *ppVfs==0 ){
    *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs);
    rc = SQLITE_ERROR;
  }
 parse_uri_out:
  if( rc!=SQLITE_OK ){
    sqlite3_free_filename(zFile);
    zFile = 0;
  }
  *pFlags = flags;
  *pzFile = zFile;
  return rc;
}


/*
** This routine does the core work of extracting URI parameters from a
** database filename for the sqlite3_uri_parameter() interface.

*/
static const char *uriParameter(const char *zFilename, const char *zParam){
  zFilename += sqlite3Strlen30(zFilename) + 1;

  while( zFilename[0] ){




    int x = strcmp(zFilename, zParam);


    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }









  return 0;
}




/*
** This routine does the work of opening a database on behalf of
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"  
** is UTF-8 encoded.
*/
160574
160575
160576
160577
160578
160579
160580
160581


160582
160583
160584
160585
160586
160587
160588
  db->szMmap = sqlite3GlobalConfig.szMmap;
  db->nextPagesize = 0;
  db->nMaxSorterMmap = 0x7FFFFFFF;
  db->flags |= SQLITE_ShortColNames
                 | SQLITE_EnableTrigger
                 | SQLITE_EnableView
                 | SQLITE_CacheSpill



/* The SQLITE_DQS compile-time option determines the default settings
** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML.
**
**    SQLITE_DQS     SQLITE_DBCONFIG_DQS_DDL    SQLITE_DBCONFIG_DQS_DML
**    ----------     -----------------------    -----------------------
**     undefined               on                          on   
**         3                   on                          on







|
>
>







162357
162358
162359
162360
162361
162362
162363
162364
162365
162366
162367
162368
162369
162370
162371
162372
162373
  db->szMmap = sqlite3GlobalConfig.szMmap;
  db->nextPagesize = 0;
  db->nMaxSorterMmap = 0x7FFFFFFF;
  db->flags |= SQLITE_ShortColNames
                 | SQLITE_EnableTrigger
                 | SQLITE_EnableView
                 | SQLITE_CacheSpill
#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0
                 | SQLITE_TrustedSchema
#endif
/* The SQLITE_DQS compile-time option determines the default settings
** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML.
**
**    SQLITE_DQS     SQLITE_DBCONFIG_DQS_DDL    SQLITE_DBCONFIG_DQS_DML
**    ----------     -----------------------    -----------------------
**     undefined               on                          on   
**         3                   on                          on
160654
160655
160656
160657
160658
160659
160660
160661
160662
160663
160664
160665
160666
160667
160668
160669
160670
160671
160672
  createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0);
  createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
  createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
  createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0);
  if( db->mallocFailed ){
    goto opendb_out;
  }
  /* EVIDENCE-OF: R-08308-17224 The default collating function for all
  ** strings is BINARY. 
  */
  db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0);
  assert( db->pDfltColl!=0 );

  /* Parse the filename/URI argument
  **
  ** Only allow sensible combinations of bits in the flags argument.  
  ** Throw an error if any non-sense combination is used.  If we
  ** do not block illegal combinations here, it could trigger
  ** assert() statements in deeper layers.  Sensible combinations







<
<
<
<
<







162439
162440
162441
162442
162443
162444
162445





162446
162447
162448
162449
162450
162451
162452
  createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0);
  createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
  createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
  createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0);
  if( db->mallocFailed ){
    goto opendb_out;
  }






  /* Parse the filename/URI argument
  **
  ** Only allow sensible combinations of bits in the flags argument.  
  ** Throw an error if any non-sense combination is used.  If we
  ** do not block illegal combinations here, it could trigger
  ** assert() statements in deeper layers.  Sensible combinations
160703
160704
160705
160706
160707
160708
160709
160710


160711
160712
160713
160714
160715
160716
160717
      rc = SQLITE_NOMEM_BKPT;
    }
    sqlite3Error(db, rc);
    goto opendb_out;
  }
  sqlite3BtreeEnter(db->aDb[0].pBt);
  db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
  if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);


  sqlite3BtreeLeave(db->aDb[0].pBt);
  db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);

  /* The default safety_level for the main database is FULL; for the temp
  ** database it is OFF. This matches the pager layer defaults.  
  */
  db->aDb[0].zDbSName = "main";







|
>
>







162483
162484
162485
162486
162487
162488
162489
162490
162491
162492
162493
162494
162495
162496
162497
162498
162499
      rc = SQLITE_NOMEM_BKPT;
    }
    sqlite3Error(db, rc);
    goto opendb_out;
  }
  sqlite3BtreeEnter(db->aDb[0].pBt);
  db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
  if( !db->mallocFailed ){
    sqlite3SetTextEncoding(db, SCHEMA_ENC(db));
  }
  sqlite3BtreeLeave(db->aDb[0].pBt);
  db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);

  /* The default safety_level for the main database is FULL; for the temp
  ** database it is OFF. This matches the pager layer defaults.  
  */
  db->aDb[0].zDbSName = "main";
160803
160804
160805
160806
160807
160808
160809







160810
160811
160812
160813
160814
160815
160816
#endif

#ifdef SQLITE_ENABLE_STMTVTAB
  if( !db->mallocFailed && rc==SQLITE_OK){
    rc = sqlite3StmtVtabInit(db);
  }
#endif








  /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
  ** mode.  -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
  ** mode.  Doing nothing at all also makes NORMAL the default.
  */
#ifdef SQLITE_DEFAULT_LOCKING_MODE
  db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;







>
>
>
>
>
>
>







162585
162586
162587
162588
162589
162590
162591
162592
162593
162594
162595
162596
162597
162598
162599
162600
162601
162602
162603
162604
162605
#endif

#ifdef SQLITE_ENABLE_STMTVTAB
  if( !db->mallocFailed && rc==SQLITE_OK){
    rc = sqlite3StmtVtabInit(db);
  }
#endif

#ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS
  /* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time
  ** option gives access to internal functions by default.  
  ** Testing use only!!! */
  db->mDbFlags |= DBFLAG_InternalFunc;
#endif

  /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
  ** mode.  -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
  ** mode.  Doing nothing at all also makes NORMAL the default.
  */
#ifdef SQLITE_DEFAULT_LOCKING_MODE
  db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
160844
160845
160846
160847
160848
160849
160850
160851
160852
160853
160854
160855
160856
160857
160858
160859
160860
160861
#ifdef SQLITE_ENABLE_SQLLOG
  if( sqlite3GlobalConfig.xSqllog ){
    /* Opening a db handle. Fourth parameter is passed 0. */
    void *pArg = sqlite3GlobalConfig.pSqllogArg;
    sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
  }
#endif
#if defined(SQLITE_HAS_CODEC)
  if( rc==SQLITE_OK ) sqlite3CodecQueryParameters(db, 0, zOpen);
#endif
  sqlite3_free(zOpen);
  return rc & 0xff;
}


/*
** Open a new database handle.
*/







<
<
<
|







162633
162634
162635
162636
162637
162638
162639



162640
162641
162642
162643
162644
162645
162646
162647
#ifdef SQLITE_ENABLE_SQLLOG
  if( sqlite3GlobalConfig.xSqllog ){
    /* Opening a db handle. Fourth parameter is passed 0. */
    void *pArg = sqlite3GlobalConfig.pSqllogArg;
    sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
  }
#endif



  sqlite3_free_filename(zOpen);
  return rc & 0xff;
}


/*
** Open a new database handle.
*/
161074
161075
161076
161077
161078
161079
161080
161081
161082
161083
161084
161085
161086
161087


161088
161089
161090
161091
161092
161093
161094
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse");
}
SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
}
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
  char zMsg[100];
  sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
}


SQLITE_PRIVATE int sqlite3NomemError(int lineno){
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
}
SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");







|






>
>







162860
162861
162862
162863
162864
162865
162866
162867
162868
162869
162870
162871
162872
162873
162874
162875
162876
162877
162878
162879
162880
162881
162882
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse");
}
SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
}
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)
SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
  char zMsg[100];
  sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
}
#endif
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3NomemError(int lineno){
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
}
SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){
  testcase( sqlite3GlobalConfig.xLog!=0 );
  return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
161282
161283
161284
161285
161286
161287
161288







161289
161290
161291
161292
161293
161294
161295
      *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
      *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_DATA_VERSION ){
      *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);







      rc = SQLITE_OK;
    }else{
      rc = sqlite3OsFileControl(fd, op, pArg);
    }
    sqlite3BtreeLeave(pBtree);
  }
  sqlite3_mutex_leave(db->mutex);







>
>
>
>
>
>
>







163070
163071
163072
163073
163074
163075
163076
163077
163078
163079
163080
163081
163082
163083
163084
163085
163086
163087
163088
163089
163090
      *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
      *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_DATA_VERSION ){
      *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
      int iNew = *(int*)pArg;
      *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
      if( iNew>=0 && iNew<=254 ){
        sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
      }
      rc = SQLITE_OK;
    }else{
      rc = sqlite3OsFileControl(fd, op, pArg);
    }
    sqlite3BtreeLeave(pBtree);
  }
  sqlite3_mutex_leave(db->mutex);
161342
161343
161344
161345
161346
161347
161348

161349
161350
161351
161352
161353
161354
161355
161356
161357
161358

161359
161360
161361
161362
161363
161364
161365
    **
    **    x==0 && db==0       Revert to default behavior of using the
    **                        xRandomness method on the primary VFS.
    **
    ** This test-control also resets the PRNG so that the new seed will
    ** be used for the next call to sqlite3_randomness().
    */

    case SQLITE_TESTCTRL_PRNG_SEED: {
      int x = va_arg(ap, int);
      int y;
      sqlite3 *db = va_arg(ap, sqlite3*);
      assert( db==0 || db->aDb[0].pSchema!=0 );
      if( db && (y = db->aDb[0].pSchema->schema_cookie)!=0 ){ x = y; }
      sqlite3Config.iPrngSeed = x;
      sqlite3_randomness(0,0);
      break;
    }


    /*
    **  sqlite3_test_control(BITVEC_TEST, size, program)
    **
    ** Run a test against a Bitvec object of size.  The program argument
    ** is an array of integers that defines the test.  Return -1 on a
    ** memory allocation error, 0 on success, or non-zero for an error.







>










>







163137
163138
163139
163140
163141
163142
163143
163144
163145
163146
163147
163148
163149
163150
163151
163152
163153
163154
163155
163156
163157
163158
163159
163160
163161
163162
    **
    **    x==0 && db==0       Revert to default behavior of using the
    **                        xRandomness method on the primary VFS.
    **
    ** This test-control also resets the PRNG so that the new seed will
    ** be used for the next call to sqlite3_randomness().
    */
#ifndef SQLITE_OMIT_WSD
    case SQLITE_TESTCTRL_PRNG_SEED: {
      int x = va_arg(ap, int);
      int y;
      sqlite3 *db = va_arg(ap, sqlite3*);
      assert( db==0 || db->aDb[0].pSchema!=0 );
      if( db && (y = db->aDb[0].pSchema->schema_cookie)!=0 ){ x = y; }
      sqlite3Config.iPrngSeed = x;
      sqlite3_randomness(0,0);
      break;
    }
#endif

    /*
    **  sqlite3_test_control(BITVEC_TEST, size, program)
    **
    ** Run a test against a Bitvec object of size.  The program argument
    ** is an array of integers that defines the test.  Return -1 on a
    ** memory allocation error, 0 on success, or non-zero for an error.
161497
161498
161499
161500
161501
161502
161503
161504
161505
161506
161507
161508
161509
161510
161511
161512
161513
161514
161515
161516
161517
161518
161519
161520
161521
161522
161523
161524
    **  123410     little-endian, determined at compile-time
    */ 
    case SQLITE_TESTCTRL_BYTEORDER: {
      rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
      break;
    }

    /*   sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
    **
    ** Set the nReserve size to N for the main database on the database
    ** connection db.
    */
    case SQLITE_TESTCTRL_RESERVE: {
      sqlite3 *db = va_arg(ap, sqlite3*);
      int x = va_arg(ap,int);
      sqlite3_mutex_enter(db->mutex);
      sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0);
      sqlite3_mutex_leave(db->mutex);
      break;
    }

    /*  sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N)
    **
    ** Enable or disable various optimizations for testing purposes.  The 
    ** argument N is a bitmask of optimizations to be disabled.  For normal
    ** operation N should be 0.  The idea is that a test program (like the
    ** SQL Logic Test or SLT test module) can run the same SQL multiple times
    ** with various optimizations disabled to verify that the same answer







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







163294
163295
163296
163297
163298
163299
163300














163301
163302
163303
163304
163305
163306
163307
    **  123410     little-endian, determined at compile-time
    */ 
    case SQLITE_TESTCTRL_BYTEORDER: {
      rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
      break;
    }















    /*  sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N)
    **
    ** Enable or disable various optimizations for testing purposes.  The 
    ** argument N is a bitmask of optimizations to be disabled.  For normal
    ** operation N should be 0.  The idea is that a test program (like the
    ** SQL Logic Test or SLT test module) can run the same SQL multiple times
    ** with various optimizations disabled to verify that the same answer
161536
161537
161538
161539
161540
161541
161542
161543
161544
161545
161546
161547
161548
161549
161550
161551

161552
161553
161554
161555
161556
161557
161558
    ** and its variants fail. If onoff is zero, undo this setting.
    */
    case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
      sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
      break;
    }

    /*   sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCS, int onoff);
    **
    ** If parameter onoff is non-zero, internal-use-only SQL functions
    ** are visible to ordinary SQL.  This is useful for testing but is
    ** unsafe because invalid parameters to those internal-use-only functions
    ** can result in crashes or segfaults.
    */
    case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: {
      sqlite3GlobalConfig.bInternalFunctions = va_arg(ap, int);

      break;
    }

    /*   sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int);
    **
    ** Set or clear a flag that indicates that the database file is always well-
    ** formed and never corrupt.  This flag is clear by default, indicating that







|

|
|
<
<


|
>







163319
163320
163321
163322
163323
163324
163325
163326
163327
163328
163329


163330
163331
163332
163333
163334
163335
163336
163337
163338
163339
163340
    ** and its variants fail. If onoff is zero, undo this setting.
    */
    case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
      sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
      break;
    }

    /*   sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*);
    **
    ** Toggle the ability to use internal functions on or off for
    ** the database connection given in the argument.


    */
    case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: {
      sqlite3 *db = va_arg(ap, sqlite3*);
      db->mDbFlags ^= DBFLAG_InternalFunc;
      break;
    }

    /*   sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int);
    **
    ** Set or clear a flag that indicates that the database file is always well-
    ** formed and never corrupt.  This flag is clear by default, indicating that
161680
161681
161682
161683
161684
161685
161686
161687
161688

161689


161690
161691
161692






161693





161694

161695

161696















161697





161698




161699

161700

161701






161702
161703
161704











161705
161706
161707
161708
161709
161710
161711
161712
161713
161714
161715
161716
161717
161718










161719
161720
161721
161722
161723
161724
161725
161726
161727
161728
161729
161730
161731
161732
161733
    }
  }
  va_end(ap);
#endif /* SQLITE_UNTESTABLE */
  return rc;
}

#ifdef SQLITE_DEBUG
/*

** This routine appears inside assert() statements only.


**
** Return the number of URI parameters that follow the filename.
*/






SQLITE_PRIVATE int sqlite3UriCount(const char *z){





  int n = 0;

  if( z==0 ) return 0;

  z += strlen(z)+1;















  while( z[0] ){





    z += strlen(z)+1;




    z += strlen(z)+1;

    n++;

  }






  return n;
}
#endif /* SQLITE_DEBUG */












/*
** This is a utility routine, useful to VFS implementations, that checks
** to see if a database file was a URI that contained a specific query 
** parameter, and if so obtains the value of the query parameter.
**
** The zFilename argument is the filename pointer passed into the xOpen()
** method of a VFS implementation.  The zParam argument is the name of the
** query parameter we seek.  This routine returns the value of the zParam
** parameter if it exists.  If the parameter does not exist, this routine
** returns a NULL pointer.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
  if( zFilename==0 || zParam==0 ) return 0;










  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( zFilename[0] ){
    int x = strcmp(zFilename, zParam);
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}

/*
** Return a boolean value for a query parameter.
*/
SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
  const char *z = sqlite3_uri_parameter(zFilename, zParam);







<

>
|
>
>

|

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

>
>
>
>
>
>
|

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














>
>
>
>
>
>
>
>
>
>

|
<

<


|







163462
163463
163464
163465
163466
163467
163468

163469
163470
163471
163472
163473
163474
163475
163476
163477
163478
163479
163480
163481
163482
163483
163484
163485
163486
163487
163488
163489
163490
163491
163492
163493
163494
163495
163496
163497
163498
163499
163500
163501
163502
163503
163504
163505
163506
163507
163508
163509
163510
163511
163512
163513
163514
163515
163516
163517
163518
163519
163520
163521
163522
163523
163524
163525
163526
163527
163528
163529
163530
163531
163532
163533
163534
163535
163536
163537
163538
163539
163540
163541
163542
163543
163544
163545
163546
163547
163548
163549
163550
163551
163552
163553
163554
163555
163556
163557
163558
163559
163560
163561
163562
163563
163564
163565
163566
163567
163568
163569
163570

163571

163572
163573
163574
163575
163576
163577
163578
163579
163580
163581
    }
  }
  va_end(ap);
#endif /* SQLITE_UNTESTABLE */
  return rc;
}


/*
** The Pager stores the Database filename, Journal filename, and WAL filename
** consecutively in memory, in that order.  The database filename is prefixed
** by four zero bytes.  Locate the start of the database filename by searching
** backwards for the first byte following four consecutive zero bytes.
**
** This only works if the filename passed in was obtained from the Pager.
*/
static const char *databaseName(const char *zName){
  while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
    zName--;
  }
  return zName;
}

/*
** Append text z[] to the end of p[].  Return a pointer to the first
** character after then zero terminator on the new text in p[].
*/
static char *appendText(char *p, const char *z){
  size_t n = strlen(z);
  memcpy(p, z, n+1);
  return p+n+1;
}

/*
** Allocate memory to hold names for a database, journal file, WAL file,
** and query parameters.  The pointer returned is valid for use by
** sqlite3_filename_database() and sqlite3_uri_parameter() and related
** functions.
**
** Memory layout must be compatible with that generated by the pager
** and expected by sqlite3_uri_parameter() and databaseName().
*/
SQLITE_API char *sqlite3_create_filename(
  const char *zDatabase,
  const char *zJournal,
  const char *zWal,
  int nParam,
  const char **azParam
){
  sqlite3_int64 nByte;
  int i;
  char *pResult, *p;
  nByte = strlen(zDatabase) + strlen(zJournal) + strlen(zWal) + 10;
  for(i=0; i<nParam*2; i++){
    nByte += strlen(azParam[i])+1;
  }
  pResult = p = sqlite3_malloc64( nByte );
  if( p==0 ) return 0;
  memset(p, 0, 4);
  p += 4;
  p = appendText(p, zDatabase);
  for(i=0; i<nParam*2; i++){
    p = appendText(p, azParam[i]);
  }
  *(p++) = 0;
  p = appendText(p, zJournal);
  p = appendText(p, zWal);
  *(p++) = 0;
  *(p++) = 0;
  assert( (sqlite3_int64)(p - pResult)==nByte );
  return pResult + 4;
}

/*
** Free memory obtained from sqlite3_create_filename().  It is a severe
** error to call this routine with any parameter other than a pointer
** previously obtained from sqlite3_create_filename() or a NULL pointer.
*/
SQLITE_API void sqlite3_free_filename(char *p){
  if( p==0 ) return;
  p = (char*)databaseName(p);
  sqlite3_free(p - 4);
}


/*
** This is a utility routine, useful to VFS implementations, that checks
** to see if a database file was a URI that contained a specific query 
** parameter, and if so obtains the value of the query parameter.
**
** The zFilename argument is the filename pointer passed into the xOpen()
** method of a VFS implementation.  The zParam argument is the name of the
** query parameter we seek.  This routine returns the value of the zParam
** parameter if it exists.  If the parameter does not exist, this routine
** returns a NULL pointer.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
  if( zFilename==0 || zParam==0 ) return 0;
  zFilename = databaseName(zFilename);
  return uriParameter(zFilename, zParam);
}

/*
** Return a pointer to the name of Nth query parameter of the filename.
*/
SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N){
  if( zFilename==0 || N<0 ) return 0;
  zFilename = databaseName(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( zFilename[0] && (N--)>0 ){

    zFilename += sqlite3Strlen30(zFilename) + 1;

    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return zFilename[0] ? zFilename : 0;
}

/*
** Return a boolean value for a query parameter.
*/
SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
  const char *z = sqlite3_uri_parameter(zFilename, zParam);
161746
161747
161748
161749
161750
161751
161752
































161753
161754
161755
161756
161757
161758
161759
  const char *z = sqlite3_uri_parameter(zFilename, zParam);
  sqlite3_int64 v;
  if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
    bDflt = v;
  }
  return bDflt;
}

































/*
** Return the Btree pointer identified by zDbName.  Return NULL if not found.
*/
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
  int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
  return iDb<0 ? 0 : db->aDb[iDb].pBt;







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







163594
163595
163596
163597
163598
163599
163600
163601
163602
163603
163604
163605
163606
163607
163608
163609
163610
163611
163612
163613
163614
163615
163616
163617
163618
163619
163620
163621
163622
163623
163624
163625
163626
163627
163628
163629
163630
163631
163632
163633
163634
163635
163636
163637
163638
163639
  const char *z = sqlite3_uri_parameter(zFilename, zParam);
  sqlite3_int64 v;
  if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
    bDflt = v;
  }
  return bDflt;
}

/*
** Translate a filename that was handed to a VFS routine into the corresponding
** database, journal, or WAL file.
**
** It is an error to pass this routine a filename string that was not
** passed into the VFS from the SQLite core.  Doing so is similar to
** passing free() a pointer that was not obtained from malloc() - it is
** an error that we cannot easily detect but that will likely cause memory
** corruption.
*/
SQLITE_API const char *sqlite3_filename_database(const char *zFilename){
  return databaseName(zFilename);
}
SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){
  zFilename = databaseName(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( zFilename[0] ){
    zFilename += sqlite3Strlen30(zFilename) + 1;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return zFilename + 1;
}
SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){
#ifdef SQLITE_OMIT_WAL
  return 0;
#else
  zFilename = sqlite3_filename_journal(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  return zFilename;
#endif
}

/*
** Return the Btree pointer identified by zDbName.  Return NULL if not found.
*/
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
  int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
  return iDb<0 ? 0 : db->aDb[iDb].pBt;
163080
163081
163082
163083
163084
163085
163086



163087
163088
163089
163090
163091
163092
163093
*/
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
# define TESTONLY(X)  X
#else
# define TESTONLY(X)
#endif




#endif /* SQLITE_AMALGAMATION */

#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3Fts3Corrupt(void);
# define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt()
#else
# define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB







>
>
>







164960
164961
164962
164963
164964
164965
164966
164967
164968
164969
164970
164971
164972
164973
164974
164975
164976
*/
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
# define TESTONLY(X)  X
#else
# define TESTONLY(X)
#endif

#define LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)

#endif /* SQLITE_AMALGAMATION */

#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3Fts3Corrupt(void);
# define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt()
#else
# define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB
163123
163124
163125
163126
163127
163128
163129

163130
163131
163132
163133
163134
163135
163136
  char **azColumn;                /* column names.  malloced */
  u8 *abNotindexed;               /* True for 'notindexed' columns */
  sqlite3_tokenizer *pTokenizer;  /* tokenizer for inserts and queries */
  char *zContentTbl;              /* content=xxx option, or NULL */
  char *zLanguageid;              /* languageid=xxx option, or NULL */
  int nAutoincrmerge;             /* Value configured by 'automerge' */
  u32 nLeafAdd;                   /* Number of leaf blocks added this trans */


  /* Precompiled statements used by the implementation. Each of these 
  ** statements is run and reset within a single virtual table API call. 
  */
  sqlite3_stmt *aStmt[40];
  sqlite3_stmt *pSeekStmt;        /* Cache for fts3CursorSeekStmt() */








>







165006
165007
165008
165009
165010
165011
165012
165013
165014
165015
165016
165017
165018
165019
165020
  char **azColumn;                /* column names.  malloced */
  u8 *abNotindexed;               /* True for 'notindexed' columns */
  sqlite3_tokenizer *pTokenizer;  /* tokenizer for inserts and queries */
  char *zContentTbl;              /* content=xxx option, or NULL */
  char *zLanguageid;              /* languageid=xxx option, or NULL */
  int nAutoincrmerge;             /* Value configured by 'automerge' */
  u32 nLeafAdd;                   /* Number of leaf blocks added this trans */
  int bLock;                      /* Used to prevent recursive content= tbls */

  /* Precompiled statements used by the implementation. Each of these 
  ** statements is run and reset within a single virtual table API call. 
  */
  sqlite3_stmt *aStmt[40];
  sqlite3_stmt *pSeekStmt;        /* Cache for fts3CursorSeekStmt() */

163461
163462
163463
163464
163465
163466
163467

163468
163469
163470
163471
163472
163473
163474
  (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \
)

/* fts3.c */
SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...);
SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64);
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);

SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*);
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);







>







165345
165346
165347
165348
165349
165350
165351
165352
165353
165354
165355
165356
165357
165358
165359
  (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \
)

/* fts3.c */
SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...);
SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64);
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *);
SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*);
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
163548
163549
163550
163551
163552
163553
163554
163555
163556
163557
163558
163559
163560
163561
163562
163563
163564
163565
163566
163567
163568
163569
163570
163571
163572
163573

/* #include "fts3.h" */
#ifndef SQLITE_CORE 
/* # include "sqlite3ext.h" */
  SQLITE_EXTENSION_INIT1
#endif

/*
** The following are copied from sqliteInt.h.
**
** Constants for the largest and smallest possible 64-bit signed integers.
** These macros are designed to work correctly on both 32-bit and 64-bit
** compilers.
*/
#ifndef SQLITE_AMALGAMATION
# define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
#endif

static int fts3EvalNext(Fts3Cursor *pCsr);
static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor(
    Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **);

#ifndef SQLITE_AMALGAMATION
# if defined(SQLITE_DEBUG)







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







165433
165434
165435
165436
165437
165438
165439












165440
165441
165442
165443
165444
165445
165446

/* #include "fts3.h" */
#ifndef SQLITE_CORE 
/* # include "sqlite3ext.h" */
  SQLITE_EXTENSION_INIT1
#endif













static int fts3EvalNext(Fts3Cursor *pCsr);
static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor(
    Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **);

#ifndef SQLITE_AMALGAMATION
# if defined(SQLITE_DEBUG)
163604
163605
163606
163607
163608
163609
163610
163611
163612
163613
163614
163615
163616
163617
163618
163619
163620
163621
163622
163623
163624
163625
163626
163627
163628
163629
163630
163631
163632
163633
163634
163635
163636









163637
163638
163639
163640
163641
163642
163643
#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \
  v = (v & mask1) | ( (*(const unsigned char*)(ptr++)) << shift );  \
  if( (v & mask2)==0 ){ var = v; return ret; }
#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \
  v = (*ptr++);                                               \
  if( (v & mask2)==0 ){ var = v; return ret; }

/* 
** Read a 64-bit variable-length integer from memory starting at p[0].
** Return the number of bytes read, or 0 on error.
** The value is stored in *v.
*/
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
  const unsigned char *p = (const unsigned char*)pBuf;
  const unsigned char *pStart = p;
  u32 a;
  u64 b;
  int shift;

  GETVARINT_INIT(a, p, 0,  0x00,     0x80, *v, 1);
  GETVARINT_STEP(a, p, 7,  0x7F,     0x4000, *v, 2);
  GETVARINT_STEP(a, p, 14, 0x3FFF,   0x200000, *v, 3);
  GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *v, 4);
  b = (a & 0x0FFFFFFF );

  for(shift=28; shift<=63; shift+=7){
    u64 c = *p++;
    b += (c&0x7F) << shift;
    if( (c & 0x80)==0 ) break;
  }
  *v = b;
  return (int)(p - pStart);
}










/* 
** Read a 64-bit variable-length integer from memory starting at p[0] and
** not extending past pEnd[-1].
** Return the number of bytes read, or 0 on error.
** The value is stored in *v.
*/







<
<
<
<
<
|




















>
>
>
>
>
>
>
>
>







165477
165478
165479
165480
165481
165482
165483





165484
165485
165486
165487
165488
165489
165490
165491
165492
165493
165494
165495
165496
165497
165498
165499
165500
165501
165502
165503
165504
165505
165506
165507
165508
165509
165510
165511
165512
165513
165514
165515
165516
165517
165518
165519
165520
#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \
  v = (v & mask1) | ( (*(const unsigned char*)(ptr++)) << shift );  \
  if( (v & mask2)==0 ){ var = v; return ret; }
#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \
  v = (*ptr++);                                               \
  if( (v & mask2)==0 ){ var = v; return ret; }






SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
  const unsigned char *p = (const unsigned char*)pBuf;
  const unsigned char *pStart = p;
  u32 a;
  u64 b;
  int shift;

  GETVARINT_INIT(a, p, 0,  0x00,     0x80, *v, 1);
  GETVARINT_STEP(a, p, 7,  0x7F,     0x4000, *v, 2);
  GETVARINT_STEP(a, p, 14, 0x3FFF,   0x200000, *v, 3);
  GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *v, 4);
  b = (a & 0x0FFFFFFF );

  for(shift=28; shift<=63; shift+=7){
    u64 c = *p++;
    b += (c&0x7F) << shift;
    if( (c & 0x80)==0 ) break;
  }
  *v = b;
  return (int)(p - pStart);
}

/* 
** Read a 64-bit variable-length integer from memory starting at p[0].
** Return the number of bytes read, or 0 on error.
** The value is stored in *v.
*/
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
  return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v);
}

/* 
** Read a 64-bit variable-length integer from memory starting at p[0] and
** not extending past pEnd[-1].
** Return the number of bytes read, or 0 on error.
** The value is stored in *v.
*/
164850
164851
164852
164853
164854
164855
164856




164857
164858
164859
164860
164861
164862
164863
  int i;                          /* Iterator variable */
  int iCons = -1;                 /* Index of constraint to use */

  int iLangidCons = -1;           /* Index of langid=x constraint, if present */
  int iDocidGe = -1;              /* Index of docid>=x constraint, if present */
  int iDocidLe = -1;              /* Index of docid<=x constraint, if present */
  int iIdx;





  /* By default use a full table scan. This is an expensive option,
  ** so search through the constraints to see if a more efficient 
  ** strategy is possible.
  */
  pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
  pInfo->estimatedCost = 5000000;







>
>
>
>







166727
166728
166729
166730
166731
166732
166733
166734
166735
166736
166737
166738
166739
166740
166741
166742
166743
166744
  int i;                          /* Iterator variable */
  int iCons = -1;                 /* Index of constraint to use */

  int iLangidCons = -1;           /* Index of langid=x constraint, if present */
  int iDocidGe = -1;              /* Index of docid>=x constraint, if present */
  int iDocidLe = -1;              /* Index of docid<=x constraint, if present */
  int iIdx;

  if( p->bLock ){
    return SQLITE_ERROR;
  }

  /* By default use a full table scan. This is an expensive option,
  ** so search through the constraints to see if a more efficient 
  ** strategy is possible.
  */
  pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
  pInfo->estimatedCost = 5000000;
165049
165050
165051
165052
165053
165054
165055


165056


165057
165058
165059
165060
165061
165062
165063
165064
165065
165066
165067
165068
165069
165070
165071
165072
165073


165074
165075
165076

165077
165078

165079
165080
165081
165082
165083
165084
165085
    char *zSql;
    if( p->pSeekStmt ){
      pCsr->pStmt = p->pSeekStmt;
      p->pSeekStmt = 0;
    }else{
      zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
      if( !zSql ) return SQLITE_NOMEM;


      rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);


      sqlite3_free(zSql);
    }
    if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
  }
  return rc;
}

/*
** Position the pCsr->pStmt statement so that it is on the row
** of the %_content table that contains the last match.  Return
** SQLITE_OK on success.  
*/
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
  int rc = SQLITE_OK;
  if( pCsr->isRequireSeek ){
    rc = fts3CursorSeekStmt(pCsr);
    if( rc==SQLITE_OK ){


      sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
      pCsr->isRequireSeek = 0;
      if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){

        return SQLITE_OK;
      }else{

        rc = sqlite3_reset(pCsr->pStmt);
        if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
          /* If no row was found and no error has occurred, then the %_content
          ** table is missing a row that is present in the full-text index.
          ** The data structures are corrupt.  */
          rc = FTS_CORRUPT_VTAB;
          pCsr->isEof = 1;







>
>
|
>
>

















>
>



>


>







166930
166931
166932
166933
166934
166935
166936
166937
166938
166939
166940
166941
166942
166943
166944
166945
166946
166947
166948
166949
166950
166951
166952
166953
166954
166955
166956
166957
166958
166959
166960
166961
166962
166963
166964
166965
166966
166967
166968
166969
166970
166971
166972
166973
166974
    char *zSql;
    if( p->pSeekStmt ){
      pCsr->pStmt = p->pSeekStmt;
      p->pSeekStmt = 0;
    }else{
      zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
      if( !zSql ) return SQLITE_NOMEM;
      p->bLock++;
      rc = sqlite3_prepare_v3(
          p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
      );
      p->bLock--;
      sqlite3_free(zSql);
    }
    if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
  }
  return rc;
}

/*
** Position the pCsr->pStmt statement so that it is on the row
** of the %_content table that contains the last match.  Return
** SQLITE_OK on success.  
*/
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
  int rc = SQLITE_OK;
  if( pCsr->isRequireSeek ){
    rc = fts3CursorSeekStmt(pCsr);
    if( rc==SQLITE_OK ){
      Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
      pTab->bLock++;
      sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
      pCsr->isRequireSeek = 0;
      if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
        pTab->bLock--;
        return SQLITE_OK;
      }else{
        pTab->bLock--;
        rc = sqlite3_reset(pCsr->pStmt);
        if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
          /* If no row was found and no error has occurred, then the %_content
          ** table is missing a row that is present in the full-text index.
          ** The data structures are corrupt.  */
          rc = FTS_CORRUPT_VTAB;
          pCsr->isEof = 1;
165120
165121
165122
165123
165124
165125
165126

165127
165128
165129
165130
165131
165132
165133
  int rc = SQLITE_OK;             /* Return code */
  const char *zCsr = zNode;       /* Cursor to iterate through node */
  const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
  char *zBuffer = 0;              /* Buffer to load terms into */
  i64 nAlloc = 0;                 /* Size of allocated buffer */
  int isFirstTerm = 1;            /* True when processing first term on page */
  sqlite3_int64 iChild;           /* Block id of child node to descend to */


  /* Skip over the 'height' varint that occurs at the start of every 
  ** interior node. Then load the blockid of the left-child of the b-tree
  ** node into variable iChild.  
  **
  ** Even if the data structure on disk is corrupted, this (reading two
  ** varints from the buffer) does not risk an overread. If zNode is a







>







167009
167010
167011
167012
167013
167014
167015
167016
167017
167018
167019
167020
167021
167022
167023
  int rc = SQLITE_OK;             /* Return code */
  const char *zCsr = zNode;       /* Cursor to iterate through node */
  const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
  char *zBuffer = 0;              /* Buffer to load terms into */
  i64 nAlloc = 0;                 /* Size of allocated buffer */
  int isFirstTerm = 1;            /* True when processing first term on page */
  sqlite3_int64 iChild;           /* Block id of child node to descend to */
  int nBuffer = 0;                /* Total term size */

  /* Skip over the 'height' varint that occurs at the start of every 
  ** interior node. Then load the blockid of the left-child of the b-tree
  ** node into variable iChild.  
  **
  ** Even if the data structure on disk is corrupted, this (reading two
  ** varints from the buffer) does not risk an overread. If zNode is a
165144
165145
165146
165147
165148
165149
165150
165151
165152
165153
165154
165155
165156




165157
165158
165159
165160
165161
165162
165163
    return FTS_CORRUPT_VTAB;
  }
  
  while( zCsr<zEnd && (piFirst || piLast) ){
    int cmp;                      /* memcmp() result */
    int nSuffix;                  /* Size of term suffix */
    int nPrefix = 0;              /* Size of term prefix */
    int nBuffer;                  /* Total term size */
  
    /* Load the next term on the node into zBuffer. Use realloc() to expand
    ** the size of zBuffer if required.  */
    if( !isFirstTerm ){
      zCsr += fts3GetVarint32(zCsr, &nPrefix);




    }
    isFirstTerm = 0;
    zCsr += fts3GetVarint32(zCsr, &nSuffix);
    
    assert( nPrefix>=0 && nSuffix>=0 );
    if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){
      rc = FTS_CORRUPT_VTAB;







<





>
>
>
>







167034
167035
167036
167037
167038
167039
167040

167041
167042
167043
167044
167045
167046
167047
167048
167049
167050
167051
167052
167053
167054
167055
167056
    return FTS_CORRUPT_VTAB;
  }
  
  while( zCsr<zEnd && (piFirst || piLast) ){
    int cmp;                      /* memcmp() result */
    int nSuffix;                  /* Size of term suffix */
    int nPrefix = 0;              /* Size of term prefix */

  
    /* Load the next term on the node into zBuffer. Use realloc() to expand
    ** the size of zBuffer if required.  */
    if( !isFirstTerm ){
      zCsr += fts3GetVarint32(zCsr, &nPrefix);
      if( nPrefix>nBuffer ){
        rc = FTS_CORRUPT_VTAB;
        goto finish_scan;
      }
    }
    isFirstTerm = 0;
    zCsr += fts3GetVarint32(zCsr, &nSuffix);
    
    assert( nPrefix>=0 && nSuffix>=0 );
    if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){
      rc = FTS_CORRUPT_VTAB;
165243
165244
165245
165246
165247
165248
165249
165250
165251
165252
165253
165254
165255
165256
165257
  int rc = SQLITE_OK;             /* Return code */
  int iHeight;                    /* Height of this node in tree */

  assert( piLeaf || piLeaf2 );

  fts3GetVarint32(zNode, &iHeight);
  rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
  assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );

  if( rc==SQLITE_OK && iHeight>1 ){
    char *zBlob = 0;              /* Blob read from %_segments table */
    int nBlob = 0;                /* Size of zBlob in bytes */

    if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
      rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0);







|







167136
167137
167138
167139
167140
167141
167142
167143
167144
167145
167146
167147
167148
167149
167150
  int rc = SQLITE_OK;             /* Return code */
  int iHeight;                    /* Height of this node in tree */

  assert( piLeaf || piLeaf2 );

  fts3GetVarint32(zNode, &iHeight);
  rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
  assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );

  if( rc==SQLITE_OK && iHeight>1 ){
    char *zBlob = 0;              /* Blob read from %_segments table */
    int nBlob = 0;                /* Size of zBlob in bytes */

    if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
      rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0);
165724
165725
165726
165727
165728
165729
165730
165731
165732
165733
165734
165735
165736
165737
165738
165739
165740
165741
165742
165743
  char *pEnd,                     /* End of buffer */
  int bDescIdx,                   /* True if docids are descending */
  sqlite3_int64 *pVal             /* IN/OUT: Integer value */
){
  if( *pp>=pEnd ){
    *pp = 0;
  }else{
    sqlite3_int64 iVal;
    *pp += sqlite3Fts3GetVarint(*pp, &iVal);
    if( bDescIdx ){
      *pVal -= iVal;
    }else{
      *pVal += iVal;
    }
  }
}

/*
** This function is used to write a single varint to a buffer. The varint
** is written to *pp. Before returning, *pp is set to point 1 byte past the







|
|

|

|







167617
167618
167619
167620
167621
167622
167623
167624
167625
167626
167627
167628
167629
167630
167631
167632
167633
167634
167635
167636
  char *pEnd,                     /* End of buffer */
  int bDescIdx,                   /* True if docids are descending */
  sqlite3_int64 *pVal             /* IN/OUT: Integer value */
){
  if( *pp>=pEnd ){
    *pp = 0;
  }else{
    u64 iVal;
    *pp += sqlite3Fts3GetVarintU(*pp, &iVal);
    if( bDescIdx ){
      *pVal = (i64)((u64)*pVal - iVal);
    }else{
      *pVal = (i64)((u64)*pVal + iVal);
    }
  }
}

/*
** This function is used to write a single varint to a buffer. The varint
** is written to *pp. Before returning, *pp is set to point 1 byte past the
165759
165760
165761
165762
165763
165764
165765
165766
165767
165768
165769
165770
165771
165772
165773
165774
165775
165776
165777
165778
165779
165780
165781
165782
165783
165784
165785
165786
165787

165788
165789
165790
165791
165792
165793
165794
165795
  sqlite3_int64 *piPrev,          /* IN/OUT: Previous value written to list */
  int *pbFirst,                   /* IN/OUT: True after first int written */
  sqlite3_int64 iVal              /* Write this value to the list */
){
  sqlite3_uint64 iWrite;
  if( bDescIdx==0 || *pbFirst==0 ){
    assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev );
    iWrite = iVal - *piPrev;
  }else{
    assert_fts3_nc( *piPrev>=iVal );
    iWrite = *piPrev - iVal;
  }
  assert( *pbFirst || *piPrev==0 );
  assert_fts3_nc( *pbFirst==0 || iWrite>0 );
  *pp += sqlite3Fts3PutVarint(*pp, iWrite);
  *piPrev = iVal;
  *pbFirst = 1;
}


/*
** This macro is used by various functions that merge doclists. The two
** arguments are 64-bit docid values. If the value of the stack variable
** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2). 
** Otherwise, (i2-i1).
**
** Using this makes it easier to write code that can merge doclists that are
** sorted in either ascending or descending order.
*/

#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2))

/*
** This function does an "OR" merge of two doclists (output contains all
** positions contained in either argument doclist). If the docids in the 
** input doclists are sorted in ascending order, parameter bDescDoclist
** should be false. If they are sorted in ascending order, it should be
** passed a non-zero value.







|


|


















>
|







167652
167653
167654
167655
167656
167657
167658
167659
167660
167661
167662
167663
167664
167665
167666
167667
167668
167669
167670
167671
167672
167673
167674
167675
167676
167677
167678
167679
167680
167681
167682
167683
167684
167685
167686
167687
167688
167689
  sqlite3_int64 *piPrev,          /* IN/OUT: Previous value written to list */
  int *pbFirst,                   /* IN/OUT: True after first int written */
  sqlite3_int64 iVal              /* Write this value to the list */
){
  sqlite3_uint64 iWrite;
  if( bDescIdx==0 || *pbFirst==0 ){
    assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev );
    iWrite = (u64)iVal - (u64)*piPrev;
  }else{
    assert_fts3_nc( *piPrev>=iVal );
    iWrite = (u64)*piPrev - (u64)iVal;
  }
  assert( *pbFirst || *piPrev==0 );
  assert_fts3_nc( *pbFirst==0 || iWrite>0 );
  *pp += sqlite3Fts3PutVarint(*pp, iWrite);
  *piPrev = iVal;
  *pbFirst = 1;
}


/*
** This macro is used by various functions that merge doclists. The two
** arguments are 64-bit docid values. If the value of the stack variable
** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2). 
** Otherwise, (i2-i1).
**
** Using this makes it easier to write code that can merge doclists that are
** sorted in either ascending or descending order.
*/
/* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */
#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1)))

/*
** This function does an "OR" merge of two doclists (output contains all
** positions contained in either argument doclist). If the docids in the 
** input doclists are sorted in ascending order, parameter bDescDoclist
** should be false. If they are sorted in ascending order, it should be
** passed a non-zero value.
166195
166196
166197
166198
166199
166200
166201
166202
166203
166204
166205
166206
166207
166208
166209

  /* If iLevel is less than 0 and this is not a scan, include a seg-reader 
  ** for the pending-terms. If this is a scan, then this call must be being
  ** made by an fts4aux module, not an FTS table. In this case calling
  ** Fts3SegReaderPending might segfault, as the data structures used by 
  ** fts4aux are not completely populated. So it's easiest to filter these
  ** calls out here.  */
  if( iLevel<0 && p->aIndex ){
    Fts3SegReader *pSeg = 0;
    rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg);
    if( rc==SQLITE_OK && pSeg ){
      rc = fts3SegReaderCursorAppend(pCsr, pSeg);
    }
  }








|







168089
168090
168091
168092
168093
168094
168095
168096
168097
168098
168099
168100
168101
168102
168103

  /* If iLevel is less than 0 and this is not a scan, include a seg-reader 
  ** for the pending-terms. If this is a scan, then this call must be being
  ** made by an fts4aux module, not an FTS table. In this case calling
  ** Fts3SegReaderPending might segfault, as the data structures used by 
  ** fts4aux are not completely populated. So it's easiest to filter these
  ** calls out here.  */
  if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){
    Fts3SegReader *pSeg = 0;
    rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg);
    if( rc==SQLITE_OK && pSeg ){
      rc = fts3SegReaderCursorAppend(pCsr, pSeg);
    }
  }

166458
166459
166460
166461
166462
166463
166464


166465
166466
166467
166468
166469
166470
166471

166472
166473
166474
166475
166476
166477
166478
** even if we reach end-of-file.  The fts3EofMethod() will be called
** subsequently to determine whether or not an EOF was hit.
*/
static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
  int rc;
  Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
  if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){


    if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
      pCsr->isEof = 1;
      rc = sqlite3_reset(pCsr->pStmt);
    }else{
      pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
      rc = SQLITE_OK;
    }

  }else{
    rc = fts3EvalNext((Fts3Cursor *)pCursor);
  }
  assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
  return rc;
}








>
>







>







168352
168353
168354
168355
168356
168357
168358
168359
168360
168361
168362
168363
168364
168365
168366
168367
168368
168369
168370
168371
168372
168373
168374
168375
** even if we reach end-of-file.  The fts3EofMethod() will be called
** subsequently to determine whether or not an EOF was hit.
*/
static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
  int rc;
  Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
  if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){
    Fts3Table *pTab = (Fts3Table*)pCursor->pVtab;
    pTab->bLock++;
    if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
      pCsr->isEof = 1;
      rc = sqlite3_reset(pCsr->pStmt);
    }else{
      pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
      rc = SQLITE_OK;
    }
    pTab->bLock--;
  }else{
    rc = fts3EvalNext((Fts3Cursor *)pCursor);
  }
  assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
  return rc;
}

166524
166525
166526
166527
166528
166529
166530




166531
166532
166533
166534
166535
166536
166537
  sqlite3_value *pLangid = 0;     /* The "langid = ?" constraint, if any */
  sqlite3_value *pDocidGe = 0;    /* The "docid >= ?" constraint, if any */
  sqlite3_value *pDocidLe = 0;    /* The "docid <= ?" constraint, if any */
  int iIdx;

  UNUSED_PARAMETER(idxStr);
  UNUSED_PARAMETER(nVal);





  eSearch = (idxNum & 0x0000FFFF);
  assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
  assert( p->pSegments==0 );

  /* Collect arguments into local variables */
  iIdx = 0;







>
>
>
>







168421
168422
168423
168424
168425
168426
168427
168428
168429
168430
168431
168432
168433
168434
168435
168436
168437
168438
  sqlite3_value *pLangid = 0;     /* The "langid = ?" constraint, if any */
  sqlite3_value *pDocidGe = 0;    /* The "docid >= ?" constraint, if any */
  sqlite3_value *pDocidLe = 0;    /* The "docid <= ?" constraint, if any */
  int iIdx;

  UNUSED_PARAMETER(idxStr);
  UNUSED_PARAMETER(nVal);

  if( p->bLock ){
    return SQLITE_ERROR;
  }

  eSearch = (idxNum & 0x0000FFFF);
  assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
  assert( p->pSegments==0 );

  /* Collect arguments into local variables */
  iIdx = 0;
166596
166597
166598
166599
166600
166601
166602


166603


166604
166605
166606
166607
166608
166609
166610
      );
    }else{
      zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", 
          p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
      );
    }
    if( zSql ){


      rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);


      sqlite3_free(zSql);
    }else{
      rc = SQLITE_NOMEM;
    }
  }else if( eSearch==FTS3_DOCID_SEARCH ){
    rc = fts3CursorSeekStmt(pCsr);
    if( rc==SQLITE_OK ){







>
>
|
>
>







168497
168498
168499
168500
168501
168502
168503
168504
168505
168506
168507
168508
168509
168510
168511
168512
168513
168514
168515
      );
    }else{
      zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", 
          p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
      );
    }
    if( zSql ){
      p->bLock++;
      rc = sqlite3_prepare_v3(
          p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
      );
      p->bLock--;
      sqlite3_free(zSql);
    }else{
      rc = SQLITE_NOMEM;
    }
  }else if( eSearch==FTS3_DOCID_SEARCH ){
    rc = fts3CursorSeekStmt(pCsr);
    if( rc==SQLITE_OK ){
167755
167756
167757
167758
167759
167760
167761
167762
167763
167764
167765

167766
167767
167768
167769
167770
167771
167772
167773
167774
167775
167776
167777
*/
static void fts3EvalDlPhraseNext(
  Fts3Table *pTab,
  Fts3Doclist *pDL,
  u8 *pbEof
){
  char *pIter;                            /* Used to iterate through aAll */
  char *pEnd = &pDL->aAll[pDL->nAll];     /* 1 byte past end of aAll */
 
  if( pDL->pNextDocid ){
    pIter = pDL->pNextDocid;

  }else{
    pIter = pDL->aAll;
  }

  if( pIter>=pEnd ){
    /* We have already reached the end of this doclist. EOF. */
    *pbEof = 1;
  }else{
    sqlite3_int64 iDelta;
    pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
    if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
      pDL->iDocid += iDelta;







|



>




|







169660
169661
169662
169663
169664
169665
169666
169667
169668
169669
169670
169671
169672
169673
169674
169675
169676
169677
169678
169679
169680
169681
169682
169683
*/
static void fts3EvalDlPhraseNext(
  Fts3Table *pTab,
  Fts3Doclist *pDL,
  u8 *pbEof
){
  char *pIter;                            /* Used to iterate through aAll */
  char *pEnd;                             /* 1 byte past end of aAll */
 
  if( pDL->pNextDocid ){
    pIter = pDL->pNextDocid;
    assert( pDL->aAll!=0 || pIter==0 );
  }else{
    pIter = pDL->aAll;
  }

  if( pIter==0 || pIter>=(pEnd = pDL->aAll + pDL->nAll) ){
    /* We have already reached the end of this doclist. EOF. */
    *pbEof = 1;
  }else{
    sqlite3_int64 iDelta;
    pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
    if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
      pDL->iDocid += iDelta;
172670
172671
172672
172673
172674
172675
172676
172677
172678
172679
172680
172681
172682
172683
172684
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
  sqlite3 *db, 
  Fts3Hash *pHash, 
  const char *zName
){
  int rc = SQLITE_OK;
  void *p = (void *)pHash;
  const int any = SQLITE_ANY;

#ifdef SQLITE_TEST
  char *zTest = 0;
  char *zTest2 = 0;
  void *pdb = (void *)db;
  zTest = sqlite3_mprintf("%s_test", zName);
  zTest2 = sqlite3_mprintf("%s_internal_test", zName);







|







174576
174577
174578
174579
174580
174581
174582
174583
174584
174585
174586
174587
174588
174589
174590
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
  sqlite3 *db, 
  Fts3Hash *pHash, 
  const char *zName
){
  int rc = SQLITE_OK;
  void *p = (void *)pHash;
  const int any = SQLITE_UTF8|SQLITE_DIRECTONLY;

#ifdef SQLITE_TEST
  char *zTest = 0;
  char *zTest2 = 0;
  void *pdb = (void *)db;
  zTest = sqlite3_mprintf("%s_test", zName);
  zTest2 = sqlite3_mprintf("%s_internal_test", zName);
173299
173300
173301
173302
173303
173304
173305
173306
173307
173308
173309
173310
173311
173312
173313
  if( idxNum==1 ){
    const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
    int nByte = sqlite3_value_bytes(apVal[0]);
    pCsr->zInput = sqlite3_malloc64(nByte+1);
    if( pCsr->zInput==0 ){
      rc = SQLITE_NOMEM;
    }else{
      memcpy(pCsr->zInput, zByte, nByte);
      pCsr->zInput[nByte] = 0;
      rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
      if( rc==SQLITE_OK ){
        pCsr->pCsr->pTokenizer = pTab->pTok;
      }
    }
  }







|







175205
175206
175207
175208
175209
175210
175211
175212
175213
175214
175215
175216
175217
175218
175219
  if( idxNum==1 ){
    const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
    int nByte = sqlite3_value_bytes(apVal[0]);
    pCsr->zInput = sqlite3_malloc64(nByte+1);
    if( pCsr->zInput==0 ){
      rc = SQLITE_NOMEM;
    }else{
      if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte);
      pCsr->zInput[nByte] = 0;
      rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
      if( rc==SQLITE_OK ){
        pCsr->pCsr->pTokenizer = pTab->pTok;
      }
    }
  }
173742
173743
173744
173745
173746
173747
173748
173749
173750
173751
173752
173753
173754
173755
173756
/* This statement is used to determine which level to read the input from
** when performing an incremental merge. It returns the absolute level number
** of the oldest level in the db that contains at least ? segments. Or,
** if no level in the FTS index contains more than ? segments, the statement
** returns zero rows.  */
/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
         "  GROUP BY level HAVING cnt>=?"
         "  ORDER BY (level %% 1024) ASC LIMIT 1",

/* Estimate the upper limit on the number of leaf nodes in a new segment
** created by merging the oldest :2 segments from absolute level :1. See 
** function sqlite3Fts3Incrmerge() for details.  */
/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
         "  FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",








|







175648
175649
175650
175651
175652
175653
175654
175655
175656
175657
175658
175659
175660
175661
175662
/* This statement is used to determine which level to read the input from
** when performing an incremental merge. It returns the absolute level number
** of the oldest level in the db that contains at least ? segments. Or,
** if no level in the FTS index contains more than ? segments, the statement
** returns zero rows.  */
/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
         "  GROUP BY level HAVING cnt>=?"
         "  ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1",

/* Estimate the upper limit on the number of leaf nodes in a new segment
** created by merging the oldest :2 segments from absolute level :1. See 
** function sqlite3Fts3Incrmerge() for details.  */
/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
         "  FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",

174103
174104
174105
174106
174107
174108
174109
174110
174111
174112
174113
174114
174115
174116
174117
){
  PendingList *p = *pp;
  int rc = SQLITE_OK;

  assert( !p || p->iLastDocid<=iDocid );

  if( !p || p->iLastDocid!=iDocid ){
    sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0);
    if( p ){
      assert( p->nData<p->nSpace );
      assert( p->aData[p->nData]==0 );
      p->nData++;
    }
    if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iDelta)) ){
      goto pendinglistappend_out;







|







176009
176010
176011
176012
176013
176014
176015
176016
176017
176018
176019
176020
176021
176022
176023
){
  PendingList *p = *pp;
  int rc = SQLITE_OK;

  assert( !p || p->iLastDocid<=iDocid );

  if( !p || p->iLastDocid!=iDocid ){
    u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0);
    if( p ){
      assert( p->nData<p->nSpace );
      assert( p->aData[p->nData]==0 );
      p->nData++;
    }
    if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iDelta)) ){
      goto pendinglistappend_out;
174644
174645
174646
174647
174648
174649
174650


174651
174652
174653
174654
174655
174656
174657
        if( rc!=SQLITE_OK ){
          sqlite3_free(aByte);
          aByte = 0;
        }
      }
      *paBlob = aByte;
    }


  }

  return rc;
}

/*
** Close the blob handle at p->pSegments, if it is open. See comments above







>
>







176550
176551
176552
176553
176554
176555
176556
176557
176558
176559
176560
176561
176562
176563
176564
176565
        if( rc!=SQLITE_OK ){
          sqlite3_free(aByte);
          aByte = 0;
        }
      }
      *paBlob = aByte;
    }
  }else if( rc==SQLITE_ERROR ){
    rc = FTS_CORRUPT_VTAB;
  }

  return rc;
}

/*
** Close the blob handle at p->pSegments, if it is open. See comments above
174820
174821
174822
174823
174824
174825
174826

174827
174828
174829
174830
174831
174832
174833

  /* Check that the doclist does not appear to extend past the end of the
  ** b-tree node. And that the final byte of the doclist is 0x00. If either 
  ** of these statements is untrue, then the data structure is corrupt.
  */
  if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
   || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])

  ){
    return FTS_CORRUPT_VTAB;
  }
  return SQLITE_OK;
}

/*







>







176728
176729
176730
176731
176732
176733
176734
176735
176736
176737
176738
176739
176740
176741
176742

  /* Check that the doclist does not appear to extend past the end of the
  ** b-tree node. And that the final byte of the doclist is 0x00. If either 
  ** of these statements is untrue, then the data structure is corrupt.
  */
  if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
   || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
   || pReader->nDoclist==0
  ){
    return FTS_CORRUPT_VTAB;
  }
  return SQLITE_OK;
}

/*
174936
174937
174938
174939
174940
174941
174942
174943
174944
174945
174946
174947
174948
174949
174950
174951
174952
174953
174954
174955
174956
174957
174958
174959
174960
174961
    ** returning.
    */
    if( p>=pEnd ){
      pReader->pOffsetList = 0;
    }else{
      rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
      if( rc==SQLITE_OK ){
        sqlite3_int64 iDelta;
        pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
        if( pTab->bDescIdx ){
          pReader->iDocid -= iDelta;
        }else{
          pReader->iDocid += iDelta;
        }
      }
    }
  }

  return SQLITE_OK;
}


SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
  Fts3Cursor *pCsr, 
  Fts3MultiSegReader *pMsr,
  int *pnOvfl







|
|

|

|





|







176845
176846
176847
176848
176849
176850
176851
176852
176853
176854
176855
176856
176857
176858
176859
176860
176861
176862
176863
176864
176865
176866
176867
176868
176869
176870
    ** returning.
    */
    if( p>=pEnd ){
      pReader->pOffsetList = 0;
    }else{
      rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
      if( rc==SQLITE_OK ){
        u64 iDelta;
        pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta);
        if( pTab->bDescIdx ){
          pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta);
        }else{
          pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta);
        }
      }
    }
  }

  return rc;
}


SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
  Fts3Cursor *pCsr, 
  Fts3MultiSegReader *pMsr,
  int *pnOvfl
175686
175687
175688
175689
175690
175691
175692

175693
175694
175695
175696
175697
175698
175699
    sqlite3Fts3VarintLen(nDoclist) +        /* Size of doclist */
    nDoclist;                               /* Doclist data */

  if( nData>0 && nData+nReq>p->nNodeSize ){
    int rc;

    /* The current leaf node is full. Write it out to the database. */

    rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
    if( rc!=SQLITE_OK ) return rc;
    p->nLeafAdd++;

    /* Add the current term to the interior node tree. The term added to
    ** the interior tree must:
    **







>







177595
177596
177597
177598
177599
177600
177601
177602
177603
177604
177605
177606
177607
177608
177609
    sqlite3Fts3VarintLen(nDoclist) +        /* Size of doclist */
    nDoclist;                               /* Doclist data */

  if( nData>0 && nData+nReq>p->nNodeSize ){
    int rc;

    /* The current leaf node is full. Write it out to the database. */
    if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB;
    rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
    if( rc!=SQLITE_OK ) return rc;
    p->nLeafAdd++;

    /* Add the current term to the interior node tree. The term added to
    ** the interior tree must:
    **
175906
175907
175908
175909
175910
175911
175912
175913
175914
175915
175916
175917
175918
175919
175920
  ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR).
  */
  sqlite3_stmt *pStmt;
  int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
  if( rc!=SQLITE_OK ) return rc;
  sqlite3_bind_int64(pStmt, 1, iAbsLevel+1);
  sqlite3_bind_int64(pStmt, 2, 
      ((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
  );

  *pbMax = 0;
  if( SQLITE_ROW==sqlite3_step(pStmt) ){
    *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL;
  }
  return sqlite3_reset(pStmt);







|







177816
177817
177818
177819
177820
177821
177822
177823
177824
177825
177826
177827
177828
177829
177830
  ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR).
  */
  sqlite3_stmt *pStmt;
  int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
  if( rc!=SQLITE_OK ) return rc;
  sqlite3_bind_int64(pStmt, 1, iAbsLevel+1);
  sqlite3_bind_int64(pStmt, 2, 
      (((u64)iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
  );

  *pbMax = 0;
  if( SQLITE_ROW==sqlite3_step(pStmt) ){
    *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL;
  }
  return sqlite3_reset(pStmt);
176383
176384
176385
176386
176387
176388
176389
176390
176391
176392
176393
176394
176395
176396
176397
176398
176399
176400
        if( !isIgnoreEmpty || nList>0 ){

          /* Calculate the 'docid' delta value to write into the merged 
          ** doclist. */
          sqlite3_int64 iDelta;
          if( p->bDescIdx && nDoclist>0 ){
            if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB;
            iDelta = iPrev - iDocid;
          }else{
            if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
            iDelta = iDocid - iPrev;
          }

          nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
          if( nDoclist+nByte>pCsr->nBuffer ){
            char *aNew;
            pCsr->nBuffer = (nDoclist+nByte)*2;
            aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);







|


|







178293
178294
178295
178296
178297
178298
178299
178300
178301
178302
178303
178304
178305
178306
178307
178308
178309
178310
        if( !isIgnoreEmpty || nList>0 ){

          /* Calculate the 'docid' delta value to write into the merged 
          ** doclist. */
          sqlite3_int64 iDelta;
          if( p->bDescIdx && nDoclist>0 ){
            if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB;
            iDelta = (i64)((u64)iPrev - (u64)iDocid);
          }else{
            if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
            iDelta = (i64)((u64)iDocid - (u64)iPrev);
          }

          nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
          if( nDoclist+nByte>pCsr->nBuffer ){
            char *aNew;
            pCsr->nBuffer = (nDoclist+nByte)*2;
            aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
176669
176670
176671
176672
176673
176674
176675
176676
176677
176678
176679
176680
176681
176682
176683
  while( SQLITE_OK==rc ){
    rc = sqlite3Fts3SegReaderStep(p, &csr);
    if( rc!=SQLITE_ROW ) break;
    rc = fts3SegWriterAdd(p, &pWriter, 1, 
        csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
  }
  if( rc!=SQLITE_OK ) goto finished;
  assert( pWriter || bIgnoreEmpty );

  if( iLevel!=FTS3_SEGCURSOR_PENDING ){
    rc = fts3DeleteSegdir(
        p, iLangid, iIndex, iLevel, csr.apSegment, csr.nSegment
    );
    if( rc!=SQLITE_OK ) goto finished;
  }







|







178579
178580
178581
178582
178583
178584
178585
178586
178587
178588
178589
178590
178591
178592
178593
  while( SQLITE_OK==rc ){
    rc = sqlite3Fts3SegReaderStep(p, &csr);
    if( rc!=SQLITE_ROW ) break;
    rc = fts3SegWriterAdd(p, &pWriter, 1, 
        csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
  }
  if( rc!=SQLITE_OK ) goto finished;
  assert_fts3_nc( pWriter || bIgnoreEmpty );

  if( iLevel!=FTS3_SEGCURSOR_PENDING ){
    rc = fts3DeleteSegdir(
        p, iLangid, iIndex, iLevel, csr.apSegment, csr.nSegment
    );
    if( rc!=SQLITE_OK ) goto finished;
  }
178255
178256
178257
178258
178259
178260
178261
178262

178263


178264
178265
178266
178267
178268

178269
178270
178271
178272
178273
178274
178275
** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does
** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB.
*/
static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
  const int nHint = pHint->n;
  int i;

  i = pHint->n-2;

  while( i>0 && (pHint->a[i-1] & 0x80) ) i--;


  while( i>0 && (pHint->a[i-1] & 0x80) ) i--;

  pHint->n = i;
  i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
  i += fts3GetVarint32(&pHint->a[i], pnInput);

  if( i!=nHint ) return FTS_CORRUPT_VTAB;

  return SQLITE_OK;
}


/*







|
>

>
>





>







180165
180166
180167
180168
180169
180170
180171
180172
180173
180174
180175
180176
180177
180178
180179
180180
180181
180182
180183
180184
180185
180186
180187
180188
180189
** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does
** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB.
*/
static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
  const int nHint = pHint->n;
  int i;

  i = pHint->n-1;
  if( (pHint->a[i] & 0x80) ) return FTS_CORRUPT_VTAB;
  while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
  if( i==0 ) return FTS_CORRUPT_VTAB;
  i--;
  while( i>0 && (pHint->a[i-1] & 0x80) ) i--;

  pHint->n = i;
  i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
  i += fts3GetVarint32(&pHint->a[i], pnInput);
  assert( i<=nHint );
  if( i!=nHint ) return FTS_CORRUPT_VTAB;

  return SQLITE_OK;
}


/*
178331
178332
178333
178334
178335
178336
178337






178338
178339
178340
178341
178342
178343
178344
178345
178346
178347
178348
178349
178350
178351





178352

178353
178354
178355
178356
178357
178358
178359
    if( rc==SQLITE_OK && hint.n ){
      int nHint = hint.n;
      sqlite3_int64 iHintAbsLevel = 0;      /* Hint level */
      int nHintSeg = 0;                     /* Hint number of segments */

      rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg);
      if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){






        iAbsLevel = iHintAbsLevel;
        nSeg = nHintSeg;
        bUseHint = 1;
        bDirtyHint = 1;
      }else{
        /* This undoes the effect of the HintPop() above - so that no entry
        ** is removed from the hint blob.  */
        hint.n = nHint;
      }
    }

    /* If nSeg is less that zero, then there is no level with at least
    ** nMin segments and no hint in the %_stat table. No work to do.
    ** Exit early in this case.  */





    if( nSeg<0 ) break;


    /* Open a cursor to iterate through the contents of the oldest nSeg 
    ** indexes of absolute level iAbsLevel. If this cursor is opened using 
    ** the 'hint' parameters, it is possible that there are less than nSeg
    ** segments available in level iAbsLevel. In this case, no work is
    ** done on iAbsLevel - fall through to the next iteration of the loop 
    ** to start work on some other level.  */







>
>
>
>
>
>

|












>
>
>
>
>
|
>







180245
180246
180247
180248
180249
180250
180251
180252
180253
180254
180255
180256
180257
180258
180259
180260
180261
180262
180263
180264
180265
180266
180267
180268
180269
180270
180271
180272
180273
180274
180275
180276
180277
180278
180279
180280
180281
180282
180283
180284
180285
    if( rc==SQLITE_OK && hint.n ){
      int nHint = hint.n;
      sqlite3_int64 iHintAbsLevel = 0;      /* Hint level */
      int nHintSeg = 0;                     /* Hint number of segments */

      rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg);
      if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){
        /* Based on the scan in the block above, it is known that there
        ** are no levels with a relative level smaller than that of
        ** iAbsLevel with more than nSeg segments, or if nSeg is -1, 
        ** no levels with more than nMin segments. Use this to limit the
        ** value of nHintSeg to avoid a large memory allocation in case the 
        ** merge-hint is corrupt*/
        iAbsLevel = iHintAbsLevel;
        nSeg = MIN(MAX(nMin,nSeg), nHintSeg);
        bUseHint = 1;
        bDirtyHint = 1;
      }else{
        /* This undoes the effect of the HintPop() above - so that no entry
        ** is removed from the hint blob.  */
        hint.n = nHint;
      }
    }

    /* If nSeg is less that zero, then there is no level with at least
    ** nMin segments and no hint in the %_stat table. No work to do.
    ** Exit early in this case.  */
    if( nSeg<=0 ) break;

    assert( nMod<=0x7FFFFFFF );
    if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){
      rc = FTS_CORRUPT_VTAB;
      break;
    }

    /* Open a cursor to iterate through the contents of the oldest nSeg 
    ** indexes of absolute level iAbsLevel. If this cursor is opened using 
    ** the 'hint' parameters, it is possible that there are less than nSeg
    ** segments available in level iAbsLevel. In this case, no work is
    ** done on iAbsLevel - fall through to the next iteration of the loop 
    ** to start work on some other level.  */
178591
178592
178593
178594
178595
178596
178597
178598
178599
178600
178601
178602
178603
178604
178605
178606
178607
178608
178609
178610
178611
178612
178613
178614
178615
178616
178617
178618
178619
178620
178621
178622
  if( rc==SQLITE_OK ){
    while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){
      char *pCsr = csr.aDoclist;
      char *pEnd = &pCsr[csr.nDoclist];

      i64 iDocid = 0;
      i64 iCol = 0;
      i64 iPos = 0;

      pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
      while( pCsr<pEnd ){
        i64 iVal = 0;
        pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
        if( pCsr<pEnd ){
          if( iVal==0 || iVal==1 ){
            iCol = 0;
            iPos = 0;
            if( iVal ){
              pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
            }else{
              pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
              if( p->bDescIdx ){
                iDocid -= iVal;
              }else{
                iDocid += iVal;
              }
            }
          }else{
            iPos += (iVal - 2);
            cksum = cksum ^ fts3ChecksumEntry(
                csr.zTerm, csr.nTerm, iLangid, iIndex, iDocid,
                (int)iCol, (int)iPos







|



|
|







|

|

|







180517
180518
180519
180520
180521
180522
180523
180524
180525
180526
180527
180528
180529
180530
180531
180532
180533
180534
180535
180536
180537
180538
180539
180540
180541
180542
180543
180544
180545
180546
180547
180548
  if( rc==SQLITE_OK ){
    while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){
      char *pCsr = csr.aDoclist;
      char *pEnd = &pCsr[csr.nDoclist];

      i64 iDocid = 0;
      i64 iCol = 0;
      u64 iPos = 0;

      pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
      while( pCsr<pEnd ){
        u64 iVal = 0;
        pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
        if( pCsr<pEnd ){
          if( iVal==0 || iVal==1 ){
            iCol = 0;
            iPos = 0;
            if( iVal ){
              pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
            }else{
              pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
              if( p->bDescIdx ){
                iDocid = (i64)((u64)iDocid - iVal);
              }else{
                iDocid = (i64)((u64)iDocid + iVal);
              }
            }
          }else{
            iPos += (iVal - 2);
            cksum = cksum ^ fts3ChecksumEntry(
                csr.zTerm, csr.nTerm, iLangid, iIndex, iDocid,
                (int)iCol, (int)iPos
179732
179733
179734
179735
179736
179737
179738
179739
179740
179741
179742
179743
179744
179745
179746
  sIter.iCurrent = -1;
  rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter);
  if( rc==SQLITE_OK ){

    /* Set the *pmSeen output variable. */
    for(i=0; i<nList; i++){
      if( sIter.aPhrase[i].pHead ){
        *pmSeen |= (u64)1 << i;
      }
    }

    /* Loop through all candidate snippets. Store the best snippet in 
     ** *pFragment. Store its associated 'score' in iBestScore.
     */
    pFragment->iCol = iCol;







|







181658
181659
181660
181661
181662
181663
181664
181665
181666
181667
181668
181669
181670
181671
181672
  sIter.iCurrent = -1;
  rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter);
  if( rc==SQLITE_OK ){

    /* Set the *pmSeen output variable. */
    for(i=0; i<nList; i++){
      if( sIter.aPhrase[i].pHead ){
        *pmSeen |= (u64)1 << (i%64);
      }
    }

    /* Loop through all candidate snippets. Store the best snippet in 
     ** *pFragment. Store its associated 'score' in iBestScore.
     */
    pFragment->iCol = iCol;
182884
182885
182886
182887
182888
182889
182890
182891
182892
182893
182894
182895
182896
182897
182898


























182899
182900
182901
182902






182903
182904
182905
182906
182907
182908
182909
        pRoot = &pParse->aNode[iRoot];
        pRoot->u.iAppend = iStart - iRoot;
        pRoot->jnFlags |= JNODE_APPEND;
        pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
      }
      return pNode;
    }
  }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
    if( pRoot->eType!=JSON_ARRAY ) return 0;
    i = 0;
    j = 1;
    while( safe_isdigit(zPath[j]) ){
      i = i*10 + zPath[j] - '0';
      j++;
    }


























    if( zPath[j]!=']' ){
      *pzErr = zPath;
      return 0;
    }






    zPath += j + 1;
    j = 1;
    for(;;){
      while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
        if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
        j += jsonNodeSize(&pRoot[j]);
      }







|
<






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







184810
184811
184812
184813
184814
184815
184816
184817

184818
184819
184820
184821
184822
184823
184824
184825
184826
184827
184828
184829
184830
184831
184832
184833
184834
184835
184836
184837
184838
184839
184840
184841
184842
184843
184844
184845
184846
184847
184848
184849
184850
184851
184852
184853
184854
184855
184856
184857
184858
184859
184860
184861
184862
184863
184864
184865
184866
        pRoot = &pParse->aNode[iRoot];
        pRoot->u.iAppend = iStart - iRoot;
        pRoot->jnFlags |= JNODE_APPEND;
        pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
      }
      return pNode;
    }
  }else if( zPath[0]=='[' ){

    i = 0;
    j = 1;
    while( safe_isdigit(zPath[j]) ){
      i = i*10 + zPath[j] - '0';
      j++;
    }
    if( j<2 || zPath[j]!=']' ){
      if( zPath[1]=='#' ){
        JsonNode *pBase = pRoot;
        int iBase = iRoot;
        if( pRoot->eType!=JSON_ARRAY ) return 0;
        for(;;){
          while( j<=pBase->n ){
            if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
            j += jsonNodeSize(&pBase[j]);
          }
          if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
          iBase += pBase->u.iAppend;
          pBase = &pParse->aNode[iBase];
          j = 1;
        }
        j = 2;
        if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){
          unsigned int x = 0;
          j = 3;
          do{
            x = x*10 + zPath[j] - '0';
            j++;
          }while( safe_isdigit(zPath[j]) );
          if( x>i ) return 0;
          i -= x;
        }
        if( zPath[j]!=']' ){
          *pzErr = zPath;
          return 0;
        }
      }else{
        *pzErr = zPath;
        return 0;
      }
    }
    if( pRoot->eType!=JSON_ARRAY ) return 0;
    zPath += j + 1;
    j = 1;
    for(;;){
      while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
        if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
        j += jsonNodeSize(&pRoot[j]);
      }
183768
183769
183770
183771
183772
183773
183774

183775
183776
183777
183778
183779
183780
183781
  rc = sqlite3_declare_vtab(db, 
     "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
                    "json HIDDEN,root HIDDEN)");
  if( rc==SQLITE_OK ){
    pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, sizeof(*pNew));

  }
  return rc;
}

/* destructor for json_each virtual table */
static int jsonEachDisconnect(sqlite3_vtab *pVtab){
  sqlite3_free(pVtab);







>







185725
185726
185727
185728
185729
185730
185731
185732
185733
185734
185735
185736
185737
185738
185739
  rc = sqlite3_declare_vtab(db, 
     "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
                    "json HIDDEN,root HIDDEN)");
  if( rc==SQLITE_OK ){
    pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, sizeof(*pNew));
    sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
  }
  return rc;
}

/* destructor for json_each virtual table */
static int jsonEachDisconnect(sqlite3_vtab *pVtab){
  sqlite3_free(pVtab);
184258
184259
184260
184261
184262
184263
184264




184265
184266
184267
184268
184269
184270
184271
184272
184273
184274
184275
184276
184277
184278
184279
184280
184281
     const char *zName;
     sqlite3_module *pModule;
  } aMod[] = {
    { "json_each",            &jsonEachModule               },
    { "json_tree",            &jsonTreeModule               },
  };
#endif




  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
                                 SQLITE_UTF8 | SQLITE_DETERMINISTIC,
                                 (void*)&aFunc[i].flag,
                                 aFunc[i].xFunc, 0, 0);
  }
#ifndef SQLITE_OMIT_WINDOWFUNC
  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
                SQLITE_SUBTYPE | SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
                                 aAgg[i].xStep, aAgg[i].xFinal,
                                 aAgg[i].xValue, jsonGroupInverse, 0);
  }
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
  for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);







>
>
>
>

|
<






|







186216
186217
186218
186219
186220
186221
186222
186223
186224
186225
186226
186227
186228

186229
186230
186231
186232
186233
186234
186235
186236
186237
186238
186239
186240
186241
186242
     const char *zName;
     sqlite3_module *pModule;
  } aMod[] = {
    { "json_each",            &jsonEachModule               },
    { "json_tree",            &jsonTreeModule               },
  };
#endif
  static const int enc = 
       SQLITE_UTF8 |
       SQLITE_DETERMINISTIC |
       SQLITE_INNOCUOUS;
  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc,

                                 (void*)&aFunc[i].flag,
                                 aFunc[i].xFunc, 0, 0);
  }
#ifndef SQLITE_OMIT_WINDOWFUNC
  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
                                 SQLITE_SUBTYPE | enc, 0,
                                 aAgg[i].xStep, aAgg[i].xFinal,
                                 aAgg[i].xValue, jsonGroupInverse, 0);
  }
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
  for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
184363
184364
184365
184366
184367
184368
184369

184370
184371
184372
184373
184374
184375
184376

#ifndef SQLITE_CORE
/*   #include "sqlite3ext.h" */
  SQLITE_EXTENSION_INIT1
#else
/*   #include "sqlite3.h" */
#endif


#ifndef SQLITE_AMALGAMATION
#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
typedef unsigned char u8;
typedef unsigned short u16;







>







186324
186325
186326
186327
186328
186329
186330
186331
186332
186333
186334
186335
186336
186337
186338

#ifndef SQLITE_CORE
/*   #include "sqlite3ext.h" */
  SQLITE_EXTENSION_INIT1
#else
/*   #include "sqlite3.h" */
#endif
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */

#ifndef SQLITE_AMALGAMATION
#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
typedef unsigned char u8;
typedef unsigned short u16;
184626
184627
184628
184629
184630
184631
184632






184633
184634
184635
184636
184637
184638
184639
#define RTREE_LE    0x42  /* B */
#define RTREE_LT    0x43  /* C */
#define RTREE_GE    0x44  /* D */
#define RTREE_GT    0x45  /* E */
#define RTREE_MATCH 0x46  /* F: Old-style sqlite3_rtree_geometry_callback() */
#define RTREE_QUERY 0x47  /* G: New-style sqlite3_rtree_query_callback() */








/* 
** An rtree structure node.
*/
struct RtreeNode {
  RtreeNode *pParent;         /* Parent node */
  i64 iNode;                  /* The node number */







>
>
>
>
>
>







186588
186589
186590
186591
186592
186593
186594
186595
186596
186597
186598
186599
186600
186601
186602
186603
186604
186605
186606
186607
#define RTREE_LE    0x42  /* B */
#define RTREE_LT    0x43  /* C */
#define RTREE_GE    0x44  /* D */
#define RTREE_GT    0x45  /* E */
#define RTREE_MATCH 0x46  /* F: Old-style sqlite3_rtree_geometry_callback() */
#define RTREE_QUERY 0x47  /* G: New-style sqlite3_rtree_query_callback() */

/* Special operators available only on cursors.  Needs to be consecutive
** with the normal values above, but must be less than RTREE_MATCH.  These
** are used in the cursor for contraints such as x=NULL (RTREE_FALSE) or
** x<'xyz' (RTREE_TRUE) */
#define RTREE_TRUE  0x3f  /* ? */
#define RTREE_FALSE 0x40  /* @ */

/* 
** An rtree structure node.
*/
struct RtreeNode {
  RtreeNode *pParent;         /* Parent node */
  i64 iNode;                  /* The node number */
185359
185360
185361
185362
185363
185364
185365
185366
185367
185368



185369
185370
185371
185372
185373
185374
185375
185376
185377
185378
185379
185380







185381
185382
185383
185384
185385
185386
185387
185388
185389
185390
185391
185392
185393
185394
185395
185396
185397
185398
185399
185400
185401
  *ppCursor = (sqlite3_vtab_cursor *)pCsr;

  return rc;
}


/*
** Free the RtreeCursor.aConstraint[] array and its contents.
*/
static void freeCursorConstraints(RtreeCursor *pCsr){



  if( pCsr->aConstraint ){
    int i;                        /* Used to iterate through constraint array */
    for(i=0; i<pCsr->nConstraint; i++){
      sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo;
      if( pInfo ){
        if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser);
        sqlite3_free(pInfo);
      }
    }
    sqlite3_free(pCsr->aConstraint);
    pCsr->aConstraint = 0;
  }







}

/* 
** Rtree virtual table module xClose method.
*/
static int rtreeClose(sqlite3_vtab_cursor *cur){
  Rtree *pRtree = (Rtree *)(cur->pVtab);
  int ii;
  RtreeCursor *pCsr = (RtreeCursor *)cur;
  assert( pRtree->nCursor>0 );
  freeCursorConstraints(pCsr);
  sqlite3_finalize(pCsr->pReadAux);
  sqlite3_free(pCsr->aPoint);
  for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
  sqlite3_free(pCsr);
  pRtree->nCursor--;
  nodeBlobReset(pRtree);
  return SQLITE_OK;
}

/*







|

|
>
>
>












>
>
>
>
>
>
>







<


|

<
<







187327
187328
187329
187330
187331
187332
187333
187334
187335
187336
187337
187338
187339
187340
187341
187342
187343
187344
187345
187346
187347
187348
187349
187350
187351
187352
187353
187354
187355
187356
187357
187358
187359
187360
187361
187362
187363
187364
187365

187366
187367
187368
187369


187370
187371
187372
187373
187374
187375
187376
  *ppCursor = (sqlite3_vtab_cursor *)pCsr;

  return rc;
}


/*
** Reset a cursor back to its initial state.
*/
static void resetCursor(RtreeCursor *pCsr){
  Rtree *pRtree = (Rtree *)(pCsr->base.pVtab);
  int ii;
  sqlite3_stmt *pStmt;
  if( pCsr->aConstraint ){
    int i;                        /* Used to iterate through constraint array */
    for(i=0; i<pCsr->nConstraint; i++){
      sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo;
      if( pInfo ){
        if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser);
        sqlite3_free(pInfo);
      }
    }
    sqlite3_free(pCsr->aConstraint);
    pCsr->aConstraint = 0;
  }
  for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
  sqlite3_free(pCsr->aPoint);
  pStmt = pCsr->pReadAux;
  memset(pCsr, 0, sizeof(RtreeCursor));
  pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
  pCsr->pReadAux = pStmt;

}

/* 
** Rtree virtual table module xClose method.
*/
static int rtreeClose(sqlite3_vtab_cursor *cur){
  Rtree *pRtree = (Rtree *)(cur->pVtab);

  RtreeCursor *pCsr = (RtreeCursor *)cur;
  assert( pRtree->nCursor>0 );
  resetCursor(pCsr);
  sqlite3_finalize(pCsr->pReadAux);


  sqlite3_free(pCsr);
  pRtree->nCursor--;
  nodeBlobReset(pRtree);
  return SQLITE_OK;
}

/*
185545
185546
185547
185548
185549
185550
185551
185552

185553
185554


185555
185556
185557
185558
185559
185560
185561

  /* p->iCoord might point to either a lower or upper bound coordinate
  ** in a coordinate pair.  But make pCellData point to the lower bound.
  */
  pCellData += 8 + 4*(p->iCoord&0xfe);

  assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
      || p->op==RTREE_GT || p->op==RTREE_EQ );

  assert( ((((char*)pCellData) - (char*)0)&3)==0 );  /* 4-byte aligned */
  switch( p->op ){


    case RTREE_LE:
    case RTREE_LT:
    case RTREE_EQ:
      RTREE_DECODE_COORD(eInt, pCellData, val);
      /* val now holds the lower bound of the coordinate pair */
      if( p->u.rValue>=val ) return;
      if( p->op!=RTREE_EQ ) break;  /* RTREE_LE and RTREE_LT end here */







|
>


>
>







187520
187521
187522
187523
187524
187525
187526
187527
187528
187529
187530
187531
187532
187533
187534
187535
187536
187537
187538
187539

  /* p->iCoord might point to either a lower or upper bound coordinate
  ** in a coordinate pair.  But make pCellData point to the lower bound.
  */
  pCellData += 8 + 4*(p->iCoord&0xfe);

  assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
      || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
      || p->op==RTREE_FALSE );
  assert( ((((char*)pCellData) - (char*)0)&3)==0 );  /* 4-byte aligned */
  switch( p->op ){
    case RTREE_TRUE:  return;   /* Always satisfied */
    case RTREE_FALSE: break;    /* Never satisfied */
    case RTREE_LE:
    case RTREE_LT:
    case RTREE_EQ:
      RTREE_DECODE_COORD(eInt, pCellData, val);
      /* val now holds the lower bound of the coordinate pair */
      if( p->u.rValue>=val ) return;
      if( p->op!=RTREE_EQ ) break;  /* RTREE_LE and RTREE_LT end here */
185585
185586
185587
185588
185589
185590
185591
185592

185593
185594
185595
185596


185597
185598
185599
185600
185601
185602
185603
185604
185605
185606
185607
185608
  int eInt,                  /* True if RTree holds integer coordinates */
  u8 *pCellData,             /* Raw cell content as appears on disk */
  int *peWithin              /* Adjust downward, as appropriate */
){
  RtreeDValue xN;      /* Coordinate value converted to a double */

  assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
      || p->op==RTREE_GT || p->op==RTREE_EQ );

  pCellData += 8 + p->iCoord*4;
  assert( ((((char*)pCellData) - (char*)0)&3)==0 );  /* 4-byte aligned */
  RTREE_DECODE_COORD(eInt, pCellData, xN);
  switch( p->op ){


    case RTREE_LE: if( xN <= p->u.rValue ) return;  break;
    case RTREE_LT: if( xN <  p->u.rValue ) return;  break;
    case RTREE_GE: if( xN >= p->u.rValue ) return;  break;
    case RTREE_GT: if( xN >  p->u.rValue ) return;  break;
    default:       if( xN == p->u.rValue ) return;  break;
  }
  *peWithin = NOT_WITHIN;
}

/*
** One of the cells in node pNode is guaranteed to have a 64-bit 
** integer value equal to iRowid. Return the index of this cell.







|
>




>
>
|
|
|
|
|







187563
187564
187565
187566
187567
187568
187569
187570
187571
187572
187573
187574
187575
187576
187577
187578
187579
187580
187581
187582
187583
187584
187585
187586
187587
187588
187589
  int eInt,                  /* True if RTree holds integer coordinates */
  u8 *pCellData,             /* Raw cell content as appears on disk */
  int *peWithin              /* Adjust downward, as appropriate */
){
  RtreeDValue xN;      /* Coordinate value converted to a double */

  assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
      || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
      || p->op==RTREE_FALSE );
  pCellData += 8 + p->iCoord*4;
  assert( ((((char*)pCellData) - (char*)0)&3)==0 );  /* 4-byte aligned */
  RTREE_DECODE_COORD(eInt, pCellData, xN);
  switch( p->op ){
    case RTREE_TRUE:  return;   /* Always satisfied */
    case RTREE_FALSE: break;    /* Never satisfied */
    case RTREE_LE:    if( xN <= p->u.rValue ) return;  break;
    case RTREE_LT:    if( xN <  p->u.rValue ) return;  break;
    case RTREE_GE:    if( xN >= p->u.rValue ) return;  break;
    case RTREE_GT:    if( xN >  p->u.rValue ) return;  break;
    default:          if( xN == p->u.rValue ) return;  break;
  }
  *peWithin = NOT_WITHIN;
}

/*
** One of the cells in node pNode is guaranteed to have a 64-bit 
** integer value equal to iRowid. Return the index of this cell.
186087
186088
186089
186090
186091
186092
186093
186094
186095
186096
186097
186098
186099
186100
186101
186102
186103
186104
186105
186106
186107
186108
186109
186110
186111
186112




186113




186114
186115
186116
186117
186118
186119
186120
){
  Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
  RtreeNode *pRoot = 0;
  int ii;
  int rc = SQLITE_OK;
  int iCell = 0;
  sqlite3_stmt *pStmt;

  rtreeReference(pRtree);

  /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
  freeCursorConstraints(pCsr);
  sqlite3_free(pCsr->aPoint);
  pStmt = pCsr->pReadAux;
  memset(pCsr, 0, sizeof(RtreeCursor));
  pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
  pCsr->pReadAux = pStmt;

  pCsr->iStrategy = idxNum;
  if( idxNum==1 ){
    /* Special case - lookup by rowid. */
    RtreeNode *pLeaf;        /* Leaf on which the required cell resides */
    RtreeSearchPoint *p;     /* Search point for the leaf */
    i64 iRowid = sqlite3_value_int64(argv[0]);
    i64 iNode = 0;




    rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);




    if( rc==SQLITE_OK && pLeaf!=0 ){
      p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0);
      assert( p!=0 );  /* Always returns pCsr->sPoint */
      pCsr->aNode[0] = pLeaf;
      p->id = iNode;
      p->eWithin = PARTLY_WITHIN;
      rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell);







<




|
<
<
<
<
<








>
>
>
>
|
>
>
>
>







188068
188069
188070
188071
188072
188073
188074

188075
188076
188077
188078
188079





188080
188081
188082
188083
188084
188085
188086
188087
188088
188089
188090
188091
188092
188093
188094
188095
188096
188097
188098
188099
188100
188101
188102
188103
){
  Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
  RtreeNode *pRoot = 0;
  int ii;
  int rc = SQLITE_OK;
  int iCell = 0;


  rtreeReference(pRtree);

  /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
  resetCursor(pCsr);






  pCsr->iStrategy = idxNum;
  if( idxNum==1 ){
    /* Special case - lookup by rowid. */
    RtreeNode *pLeaf;        /* Leaf on which the required cell resides */
    RtreeSearchPoint *p;     /* Search point for the leaf */
    i64 iRowid = sqlite3_value_int64(argv[0]);
    i64 iNode = 0;
    int eType = sqlite3_value_numeric_type(argv[0]);
    if( eType==SQLITE_INTEGER
     || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid)
    ){
      rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
    }else{
      rc = SQLITE_OK;
      pLeaf = 0;
    }
    if( rc==SQLITE_OK && pLeaf!=0 ){
      p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0);
      assert( p!=0 );  /* Always returns pCsr->sPoint */
      pCsr->aNode[0] = pLeaf;
      p->id = iNode;
      p->eWithin = PARTLY_WITHIN;
      rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell);
186136
186137
186138
186139
186140
186141
186142

186143
186144
186145
186146
186147
186148
186149
186150
186151
186152
186153
186154
186155
186156
186157
186158
186159
186160
186161
186162









186163
186164
186165
186166
186167
186168
186169
      }else{
        memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc);
        memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1));
        assert( (idxStr==0 && argc==0)
                || (idxStr && (int)strlen(idxStr)==argc*2) );
        for(ii=0; ii<argc; ii++){
          RtreeConstraint *p = &pCsr->aConstraint[ii];

          p->op = idxStr[ii*2];
          p->iCoord = idxStr[ii*2+1]-'0';
          if( p->op>=RTREE_MATCH ){
            /* A MATCH operator. The right-hand-side must be a blob that
            ** can be cast into an RtreeMatchArg object. One created using
            ** an sqlite3_rtree_geometry_callback() SQL user function.
            */
            rc = deserializeGeometry(argv[ii], p);
            if( rc!=SQLITE_OK ){
              break;
            }
            p->pInfo->nCoord = pRtree->nDim2;
            p->pInfo->anQueue = pCsr->anQueue;
            p->pInfo->mxLevel = pRtree->iDepth + 1;
          }else{
#ifdef SQLITE_RTREE_INT_ONLY
            p->u.rValue = sqlite3_value_int64(argv[ii]);
#else
            p->u.rValue = sqlite3_value_double(argv[ii]);
#endif









          }
        }
      }
    }
    if( rc==SQLITE_OK ){
      RtreeSearchPoint *pNew;
      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));







>














|





>
>
>
>
>
>
>
>
>







188119
188120
188121
188122
188123
188124
188125
188126
188127
188128
188129
188130
188131
188132
188133
188134
188135
188136
188137
188138
188139
188140
188141
188142
188143
188144
188145
188146
188147
188148
188149
188150
188151
188152
188153
188154
188155
188156
188157
188158
188159
188160
188161
188162
      }else{
        memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc);
        memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1));
        assert( (idxStr==0 && argc==0)
                || (idxStr && (int)strlen(idxStr)==argc*2) );
        for(ii=0; ii<argc; ii++){
          RtreeConstraint *p = &pCsr->aConstraint[ii];
          int eType = sqlite3_value_numeric_type(argv[ii]);
          p->op = idxStr[ii*2];
          p->iCoord = idxStr[ii*2+1]-'0';
          if( p->op>=RTREE_MATCH ){
            /* A MATCH operator. The right-hand-side must be a blob that
            ** can be cast into an RtreeMatchArg object. One created using
            ** an sqlite3_rtree_geometry_callback() SQL user function.
            */
            rc = deserializeGeometry(argv[ii], p);
            if( rc!=SQLITE_OK ){
              break;
            }
            p->pInfo->nCoord = pRtree->nDim2;
            p->pInfo->anQueue = pCsr->anQueue;
            p->pInfo->mxLevel = pRtree->iDepth + 1;
          }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
#ifdef SQLITE_RTREE_INT_ONLY
            p->u.rValue = sqlite3_value_int64(argv[ii]);
#else
            p->u.rValue = sqlite3_value_double(argv[ii]);
#endif
          }else{
            p->u.rValue = RTREE_ZERO;
            if( eType==SQLITE_NULL ){
              p->op = RTREE_FALSE;
            }else if( p->op==RTREE_LT || p->op==RTREE_LE ){
              p->op = RTREE_TRUE;
            }else{
              p->op = RTREE_FALSE;
            }
          }
        }
      }
    }
    if( rc==SQLITE_OK ){
      RtreeSearchPoint *pNew;
      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
187931
187932
187933
187934
187935
187936
187937








187938
187939
187940
187941
187942
187943
187944
                               pRtree->zName);
    }
  }

  sqlite3_free(zSql);
  return rc;
}









/* 
** This function is the implementation of both the xConnect and xCreate
** methods of the r-tree virtual table.
**
**   argv[0]   -> module name
**   argv[1]   -> database name







>
>
>
>
>
>
>
>







189924
189925
189926
189927
189928
189929
189930
189931
189932
189933
189934
189935
189936
189937
189938
189939
189940
189941
189942
189943
189944
189945
                               pRtree->zName);
    }
  }

  sqlite3_free(zSql);
  return rc;
}

/*
** Return the length of a token
*/
static int rtreeTokenLength(const char *z){
  int dummy = 0;
  return sqlite3GetToken((const unsigned char*)z,&dummy);
}

/* 
** This function is the implementation of both the xConnect and xCreate
** methods of the r-tree virtual table.
**
**   argv[0]   -> module name
**   argv[1]   -> database name
187968
187969
187970
187971
187972
187973
187974
187975
187976
187977
187978
187979
187980
187981
187982
187983
    "Wrong number of columns for an rtree table",         /* 1 */
    "Too few columns for an rtree table",                 /* 2 */
    "Too many columns for an rtree table",                /* 3 */
    "Auxiliary rtree columns must be last"                /* 4 */
  };

  assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
  if( argc>RTREE_MAX_AUX_COLUMN+3 ){
    *pzErr = sqlite3_mprintf("%s", aErrMsg[3]);
    return SQLITE_ERROR;
  }

  sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);

  /* Allocate the sqlite3_vtab structure */
  nDb = (int)strlen(argv[1]);







|
|







189969
189970
189971
189972
189973
189974
189975
189976
189977
189978
189979
189980
189981
189982
189983
189984
    "Wrong number of columns for an rtree table",         /* 1 */
    "Too few columns for an rtree table",                 /* 2 */
    "Too many columns for an rtree table",                /* 3 */
    "Auxiliary rtree columns must be last"                /* 4 */
  };

  assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
  if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){
    *pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]);
    return SQLITE_ERROR;
  }

  sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);

  /* Allocate the sqlite3_vtab structure */
  nDb = (int)strlen(argv[1]);
187997
187998
187999
188000
188001
188002
188003
188004

188005

188006
188007
188008
188009
188010
188011

188012
188013

188014
188015
188016
188017
188018
188019
188020


  /* Create/Connect to the underlying relational database schema. If
  ** that is successful, call sqlite3_declare_vtab() to configure
  ** the r-tree table schema.
  */
  pSql = sqlite3_str_new(db);
  sqlite3_str_appendf(pSql, "CREATE TABLE x(%s", argv[3]);

  for(ii=4; ii<argc; ii++){

    if( argv[ii][0]=='+' ){
      pRtree->nAux++;
      sqlite3_str_appendf(pSql, ",%s", argv[ii]+1);
    }else if( pRtree->nAux>0 ){
      break;
    }else{

      pRtree->nDim2++;
      sqlite3_str_appendf(pSql, ",%s", argv[ii]);

    }
  }
  sqlite3_str_appendf(pSql, ");");
  zSql = sqlite3_str_finish(pSql);
  if( !zSql ){
    rc = SQLITE_NOMEM;
  }else if( ii<argc ){







|
>

>
|

|



>

|
>







189998
189999
190000
190001
190002
190003
190004
190005
190006
190007
190008
190009
190010
190011
190012
190013
190014
190015
190016
190017
190018
190019
190020
190021
190022
190023
190024
190025


  /* Create/Connect to the underlying relational database schema. If
  ** that is successful, call sqlite3_declare_vtab() to configure
  ** the r-tree table schema.
  */
  pSql = sqlite3_str_new(db);
  sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT", 
                      rtreeTokenLength(argv[3]), argv[3]);
  for(ii=4; ii<argc; ii++){
    const char *zArg = argv[ii];
    if( zArg[0]=='+' ){
      pRtree->nAux++;
      sqlite3_str_appendf(pSql, ",%.*s", rtreeTokenLength(zArg+1), zArg+1);
    }else if( pRtree->nAux>0 ){
      break;
    }else{
      static const char *azFormat[] = {",%.*s REAL", ",%.*s INT"};
      pRtree->nDim2++;
      sqlite3_str_appendf(pSql, azFormat[eCoordType],
                          rtreeTokenLength(zArg), zArg);
    }
  }
  sqlite3_str_appendf(pSql, ");");
  zSql = sqlite3_str_finish(pSql);
  if( !zSql ){
    rc = SQLITE_NOMEM;
  }else if( ii<argc ){
189954
189955
189956
189957
189958
189959
189960
189961
189962
189963
189964
189965
189966
189967
189968
189969
189970
189971
189972
189973
189974
189975
189976
189977
189978
  int argc, sqlite3_value **argv        /* Parameters to the query plan */
){
  Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
  RtreeNode *pRoot = 0;
  int rc = SQLITE_OK;
  int iCell = 0;
  sqlite3_stmt *pStmt;

  rtreeReference(pRtree);

  /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
  freeCursorConstraints(pCsr);
  sqlite3_free(pCsr->aPoint);
  pStmt = pCsr->pReadAux;
  memset(pCsr, 0, sizeof(RtreeCursor));
  pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
  pCsr->pReadAux = pStmt;

  pCsr->iStrategy = idxNum;
  if( idxNum==1 ){
    /* Special case - lookup by rowid. */
    RtreeNode *pLeaf;        /* Leaf on which the required cell resides */
    RtreeSearchPoint *p;     /* Search point for the leaf */
    i64 iRowid = sqlite3_value_int64(argv[0]);







<




|
<
<
<
<
<







191959
191960
191961
191962
191963
191964
191965

191966
191967
191968
191969
191970





191971
191972
191973
191974
191975
191976
191977
  int argc, sqlite3_value **argv        /* Parameters to the query plan */
){
  Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
  RtreeNode *pRoot = 0;
  int rc = SQLITE_OK;
  int iCell = 0;


  rtreeReference(pRtree);

  /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
  resetCursor(pCsr);






  pCsr->iStrategy = idxNum;
  if( idxNum==1 ){
    /* Special case - lookup by rowid. */
    RtreeNode *pLeaf;        /* Leaf on which the required cell resides */
    RtreeSearchPoint *p;     /* Search point for the leaf */
    i64 iRowid = sqlite3_value_int64(argv[0]);
190401
190402
190403
190404
190405
190406
190407


190408



190409
190410
190411
190412
190413
190414

190415
190416
190417
190418
190419
190420
190421
190422
    void (*xFinal)(sqlite3_context*);
    const char *zName;
  } aAgg[] = {
     { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox"    },
  };
  int i;
  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){


    int enc = aFunc[i].bPure ? SQLITE_UTF8|SQLITE_DETERMINISTIC : SQLITE_UTF8;



    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
                                 enc, 0,
                                 aFunc[i].xFunc, 0, 0);
  }
  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_function(db, aAgg[i].zName, 1, SQLITE_UTF8, 0,

                                 0, aAgg[i].xStep, aAgg[i].xFinal);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0);
  }
  return rc;
}








>
>
|
>
>
>





|
>
|







192400
192401
192402
192403
192404
192405
192406
192407
192408
192409
192410
192411
192412
192413
192414
192415
192416
192417
192418
192419
192420
192421
192422
192423
192424
192425
192426
192427
    void (*xFinal)(sqlite3_context*);
    const char *zName;
  } aAgg[] = {
     { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox"    },
  };
  int i;
  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
    int enc;
    if( aFunc[i].bPure ){
      enc = SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS;
    }else{
      enc = SQLITE_UTF8|SQLITE_DIRECTONLY;
    }
    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
                                 enc, 0,
                                 aFunc[i].xFunc, 0, 0);
  }
  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_function(db, aAgg[i].zName, 1, 
              SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS, 0,
              0, aAgg[i].xStep, aAgg[i].xFinal);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0);
  }
  return rc;
}

190742
190743
190744
190745
190746
190747
190748
190749
190750
190751
190752
190753
190754
190755
190756
    /* There are now 4 possibilities:
    **
    **     1. uPattern is an unescaped match-all character "%",
    **     2. uPattern is an unescaped match-one character "_",
    **     3. uPattern is an unescaped escape character, or
    **     4. uPattern is to be handled as an ordinary character
    */
    if( !prevEscape && uPattern==MATCH_ALL ){
      /* Case 1. */
      uint8_t c;

      /* Skip any MATCH_ALL or MATCH_ONE characters that follow a
      ** MATCH_ALL. For each MATCH_ONE, skip one character in the 
      ** test string.
      */







|







192747
192748
192749
192750
192751
192752
192753
192754
192755
192756
192757
192758
192759
192760
192761
    /* There are now 4 possibilities:
    **
    **     1. uPattern is an unescaped match-all character "%",
    **     2. uPattern is an unescaped match-one character "_",
    **     3. uPattern is an unescaped escape character, or
    **     4. uPattern is to be handled as an ordinary character
    */
    if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){
      /* Case 1. */
      uint8_t c;

      /* Skip any MATCH_ALL or MATCH_ONE characters that follow a
      ** MATCH_ALL. For each MATCH_ONE, skip one character in the 
      ** test string.
      */
190768
190769
190770
190771
190772
190773
190774
190775
190776
190777
190778
190779
190780
190781
190782
190783
190784
190785
190786
190787
        if( icuLikeCompare(zPattern, zString, uEsc) ){
          return 1;
        }
        SQLITE_ICU_SKIP_UTF8(zString);
      }
      return 0;

    }else if( !prevEscape && uPattern==MATCH_ONE ){
      /* Case 2. */
      if( *zString==0 ) return 0;
      SQLITE_ICU_SKIP_UTF8(zString);

    }else if( !prevEscape && uPattern==(uint32_t)uEsc){
      /* Case 3. */
      prevEscape = 1;

    }else{
      /* Case 4. */
      uint32_t uString;
      SQLITE_ICU_READ_UTF8(zString, uString);







|




|







192773
192774
192775
192776
192777
192778
192779
192780
192781
192782
192783
192784
192785
192786
192787
192788
192789
192790
192791
192792
        if( icuLikeCompare(zPattern, zString, uEsc) ){
          return 1;
        }
        SQLITE_ICU_SKIP_UTF8(zString);
      }
      return 0;

    }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){
      /* Case 2. */
      if( *zString==0 ) return 0;
      SQLITE_ICU_SKIP_UTF8(zString);

    }else if( uPattern==(uint32_t)uEsc && !prevEscape ){
      /* Case 3. */
      prevEscape = 1;

    }else{
      /* Case 4. */
      uint32_t uString;
      SQLITE_ICU_READ_UTF8(zString, uString);
191098
191099
191100
191101
191102
191103
191104

191105
191106
191107
191108
191109
191110
191111
191112
191113
191114
191115
191116
191117
191118
191119
191120
191121
191122
191123
191124
191125
191126
191127
191128
191129
191130
191131
  }
}

/*
** Register the ICU extension functions with database db.
*/
SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){

  static const struct IcuScalar {
    const char *zName;                        /* Function name */
    unsigned char nArg;                       /* Number of arguments */
    unsigned short enc;                       /* Optimal text encoding */
    unsigned char iContext;                   /* sqlite3_user_data() context */
    void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
  } scalars[] = {
    {"icu_load_collation",  2, SQLITE_UTF8,                1, icuLoadCollation},
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
    {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC,         0, icuRegexpFunc},
    {"lower",  1, SQLITE_UTF16|SQLITE_DETERMINISTIC,       0, icuCaseFunc16},
    {"lower",  2, SQLITE_UTF16|SQLITE_DETERMINISTIC,       0, icuCaseFunc16},
    {"upper",  1, SQLITE_UTF16|SQLITE_DETERMINISTIC,       1, icuCaseFunc16},
    {"upper",  2, SQLITE_UTF16|SQLITE_DETERMINISTIC,       1, icuCaseFunc16},
    {"lower",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuCaseFunc16},
    {"lower",  2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuCaseFunc16},
    {"upper",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC,        1, icuCaseFunc16},
    {"upper",  2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        1, icuCaseFunc16},
    {"like",   2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuLikeFunc},
    {"like",   3, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuLikeFunc},
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
  };
  int rc = SQLITE_OK;
  int i;
  
  for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
    const struct IcuScalar *p = &scalars[i];







>



|



|

|
|
|
|
|
|
|
|
|
|
|







193103
193104
193105
193106
193107
193108
193109
193110
193111
193112
193113
193114
193115
193116
193117
193118
193119
193120
193121
193122
193123
193124
193125
193126
193127
193128
193129
193130
193131
193132
193133
193134
193135
193136
193137
  }
}

/*
** Register the ICU extension functions with database db.
*/
SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
  static const struct IcuScalar {
    const char *zName;                        /* Function name */
    unsigned char nArg;                       /* Number of arguments */
    unsigned int enc;                         /* Optimal text encoding */
    unsigned char iContext;                   /* sqlite3_user_data() context */
    void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
  } scalars[] = {
    {"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
    {"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS,         0, icuRegexpFunc},
    {"lower",  1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS,       0, icuCaseFunc16},
    {"lower",  2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS,       0, icuCaseFunc16},
    {"upper",  1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS,       1, icuCaseFunc16},
    {"upper",  2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS,       1, icuCaseFunc16},
    {"lower",  1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS,        0, icuCaseFunc16},
    {"lower",  2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS,        0, icuCaseFunc16},
    {"upper",  1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS,        1, icuCaseFunc16},
    {"upper",  2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS,        1, icuCaseFunc16},
    {"like",   2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS,        0, icuLikeFunc},
    {"like",   3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS,        0, icuLikeFunc},
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
  };
  int rc = SQLITE_OK;
  int i;
  
  for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
    const struct IcuScalar *p = &scalars[i];
196965
196966
196967
196968
196969
196970
196971
196972
196973
196974
196975
196976
196977
196978
196979
196980
196981
196982
196983
196984
196985
196986
196987
196988
196989
196990
196991
196992
196993
196994
196995
196996
196997
196998
196999
197000
197001
197002
197003
197004
197005
    /* Release the checkpointer and writer locks */
    rbuUnlockShm(p);
    rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
  }
  return rc;
}

/* 
** A main database named zName has just been opened. The following 
** function returns a pointer to a buffer owned by SQLite that contains
** the name of the *-wal file this db connection will use. SQLite
** happens to pass a pointer to this buffer when using xAccess()
** or xOpen() to operate on the *-wal file.  
*/
static const char *rbuMainToWal(const char *zName, int flags){
  int n = (int)strlen(zName);
  const char *z = &zName[n];
  if( flags & SQLITE_OPEN_URI ){
    int odd = 0;
    while( 1 ){
      if( z[0]==0 ){
        odd = 1 - odd;
        if( odd && z[1]==0 ) break;
      }
      z++;
    }
    z += 2;
  }else{
    while( *z==0 ) z++;
  }
  z += (n + 8 + 1);
  return z;
}

/*
** Open an rbu file handle.
*/
static int rbuVfsOpen(
  sqlite3_vfs *pVfs,
  const char *zName,
  sqlite3_file *pFile,







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







198971
198972
198973
198974
198975
198976
198977



























198978
198979
198980
198981
198982
198983
198984
    /* Release the checkpointer and writer locks */
    rbuUnlockShm(p);
    rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
  }
  return rc;
}




























/*
** Open an rbu file handle.
*/
static int rbuVfsOpen(
  sqlite3_vfs *pVfs,
  const char *zName,
  sqlite3_file *pFile,
197040
197041
197042
197043
197044
197045
197046
197047
197048
197049
197050
197051
197052
197053
197054
197055
197056
197057
197058
197059
197060
197061
197062
197063
197064
197065
197066
197067
197068
197069
  if( zName ){
    if( flags & SQLITE_OPEN_MAIN_DB ){
      /* A main database has just been opened. The following block sets
      ** (pFd->zWal) to point to a buffer owned by SQLite that contains
      ** the name of the *-wal file this db connection will use. SQLite
      ** happens to pass a pointer to this buffer when using xAccess()
      ** or xOpen() to operate on the *-wal file.  */
      pFd->zWal = rbuMainToWal(zName, flags);
    }
    else if( flags & SQLITE_OPEN_WAL ){
      rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
      if( pDb ){
        if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
          /* This call is to open a *-wal file. Intead, open the *-oal. This
          ** code ensures that the string passed to xOpen() is terminated by a
          ** pair of '\0' bytes in case the VFS attempts to extract a URI 
          ** parameter from it.  */
          const char *zBase = zName;
          size_t nCopy;
          char *zCopy;
          if( rbuIsVacuum(pDb->pRbu) ){
            zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
            zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
          }
          nCopy = strlen(zBase);
          zCopy = sqlite3_malloc64(nCopy+2);
          if( zCopy ){
            memcpy(zCopy, zBase, nCopy);
            zCopy[nCopy-3] = 'o';
            zCopy[nCopy] = '\0';







|














|







199019
199020
199021
199022
199023
199024
199025
199026
199027
199028
199029
199030
199031
199032
199033
199034
199035
199036
199037
199038
199039
199040
199041
199042
199043
199044
199045
199046
199047
199048
  if( zName ){
    if( flags & SQLITE_OPEN_MAIN_DB ){
      /* A main database has just been opened. The following block sets
      ** (pFd->zWal) to point to a buffer owned by SQLite that contains
      ** the name of the *-wal file this db connection will use. SQLite
      ** happens to pass a pointer to this buffer when using xAccess()
      ** or xOpen() to operate on the *-wal file.  */
      pFd->zWal = sqlite3_filename_wal(zName);
    }
    else if( flags & SQLITE_OPEN_WAL ){
      rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
      if( pDb ){
        if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
          /* This call is to open a *-wal file. Intead, open the *-oal. This
          ** code ensures that the string passed to xOpen() is terminated by a
          ** pair of '\0' bytes in case the VFS attempts to extract a URI 
          ** parameter from it.  */
          const char *zBase = zName;
          size_t nCopy;
          char *zCopy;
          if( rbuIsVacuum(pDb->pRbu) ){
            zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
            zBase = sqlite3_filename_wal(zBase);
          }
          nCopy = strlen(zBase);
          zCopy = sqlite3_malloc64(nCopy+2);
          if( zCopy ){
            memcpy(zCopy, zBase, nCopy);
            zCopy[nCopy-3] = 'o';
            zCopy[nCopy] = '\0';
197530
197531
197532
197533
197534
197535
197536

197537
197538
197539
197540
197541
197542
197543
    if( iDb<0 ){
      *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
      return SQLITE_ERROR;
    }
  }else{
    iDb = 0;
  }

  rc = sqlite3_declare_vtab(db, zDbstatSchema);
  if( rc==SQLITE_OK ){
    pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
  }

  assert( rc==SQLITE_OK || pTab==0 );







>







199509
199510
199511
199512
199513
199514
199515
199516
199517
199518
199519
199520
199521
199522
199523
    if( iDb<0 ){
      *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
      return SQLITE_ERROR;
    }
  }else{
    iDb = 0;
  }
  sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
  rc = sqlite3_declare_vtab(db, zDbstatSchema);
  if( rc==SQLITE_OK ){
    pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
  }

  assert( rc==SQLITE_OK || pTab==0 );
197605
197606
197607
197608
197609
197610
197611
197612
197613
197614
197615
197616
197617
197618
197619
197620
197621
197622
197623
197624
  if( iSchema>=0 ){
    pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i;
    pIdxInfo->aConstraintUsage[iSchema].omit = 1;
    pIdxInfo->idxNum |= 0x01;
  }
  if( iName>=0 ){
    pIdxInfo->aConstraintUsage[iName].argvIndex = ++i;
    pIdxInfo->aConstraintUsage[iName].omit = 1;
    pIdxInfo->idxNum |= 0x02;
  }
  if( iAgg>=0 ){
    pIdxInfo->aConstraintUsage[iAgg].argvIndex = ++i;
    pIdxInfo->aConstraintUsage[iAgg].omit = 1;
    pIdxInfo->idxNum |= 0x04;
  }
  pIdxInfo->estimatedCost = 1.0;

  /* Records are always returned in ascending order of (name, path). 
  ** If this will satisfy the client, set the orderByConsumed flag so that 
  ** SQLite does not do an external sort.







<




<







199585
199586
199587
199588
199589
199590
199591

199592
199593
199594
199595

199596
199597
199598
199599
199600
199601
199602
  if( iSchema>=0 ){
    pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i;
    pIdxInfo->aConstraintUsage[iSchema].omit = 1;
    pIdxInfo->idxNum |= 0x01;
  }
  if( iName>=0 ){
    pIdxInfo->aConstraintUsage[iName].argvIndex = ++i;

    pIdxInfo->idxNum |= 0x02;
  }
  if( iAgg>=0 ){
    pIdxInfo->aConstraintUsage[iAgg].argvIndex = ++i;

    pIdxInfo->idxNum |= 0x04;
  }
  pIdxInfo->estimatedCost = 1.0;

  /* Records are always returned in ascending order of (name, path). 
  ** If this will satisfy the client, set the orderByConsumed flag so that 
  ** SQLite does not do an external sort.
197817
197818
197819
197820
197821
197822
197823

197824

197825
197826
197827
197828
197829
197830
197831
        if( nLocal<0 ) goto statPageIsCorrupt;
        pCell->nLocal = nLocal;
        assert( nPayload>=(u32)nLocal );
        assert( nLocal<=(nUsable-35) );
        if( nPayload>(u32)nLocal ){
          int j;
          int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);

          if( iOff+nLocal>nUsable ) goto statPageIsCorrupt;

          pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
          pCell->nOvfl = nOvfl;
          pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
          if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
          pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
          for(j=1; j<nOvfl; j++){
            int rc;







>
|
>







199795
199796
199797
199798
199799
199800
199801
199802
199803
199804
199805
199806
199807
199808
199809
199810
199811
        if( nLocal<0 ) goto statPageIsCorrupt;
        pCell->nLocal = nLocal;
        assert( nPayload>=(u32)nLocal );
        assert( nLocal<=(nUsable-35) );
        if( nPayload>(u32)nLocal ){
          int j;
          int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
          if( iOff+nLocal>nUsable || nPayload>0x7fffffff ){
            goto statPageIsCorrupt;
          }
          pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
          pCell->nOvfl = nOvfl;
          pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
          if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
          pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
          for(j=1; j<nOvfl; j++){
            int rc;
198066
198067
198068
198069
198070
198071
198072
198073
198074
198075
198076
198077
198078
198079
198080
198081
198082
  sqlite3_finalize(pCsr->pStmt);
  pCsr->pStmt = 0;
  if( idxNum & 0x01 ){
    /* schema=? constraint is present.  Get its value */
    const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]);
    pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
    if( pCsr->iDb<0 ){
      sqlite3_free(pCursor->pVtab->zErrMsg);
      pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
      return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
    }
  }else{
    pCsr->iDb = pTab->iDb;
  }
  if( idxNum & 0x02 ){
    /* name=? constraint is present */
    zName = (const char*)sqlite3_value_text(argv[iArg++]);







|
|
|







200046
200047
200048
200049
200050
200051
200052
200053
200054
200055
200056
200057
200058
200059
200060
200061
200062
  sqlite3_finalize(pCsr->pStmt);
  pCsr->pStmt = 0;
  if( idxNum & 0x01 ){
    /* schema=? constraint is present.  Get its value */
    const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]);
    pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
    if( pCsr->iDb<0 ){
      pCsr->iDb = 0;
      pCsr->isEof = 1;
      return SQLITE_OK;
    }
  }else{
    pCsr->iDb = pTab->iDb;
  }
  if( idxNum & 0x02 ){
    /* name=? constraint is present */
    zName = (const char*)sqlite3_value_text(argv[iArg++]);
198291
198292
198293
198294
198295
198296
198297

198298
198299
198300
198301
198302
198303
198304
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  DbpageTable *pTab = 0;
  int rc = SQLITE_OK;


  rc = sqlite3_declare_vtab(db, 
          "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
  if( rc==SQLITE_OK ){
    pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
  }








>







200271
200272
200273
200274
200275
200276
200277
200278
200279
200280
200281
200282
200283
200284
200285
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  DbpageTable *pTab = 0;
  int rc = SQLITE_OK;

  sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
  rc = sqlite3_declare_vtab(db, 
          "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
  if( rc==SQLITE_OK ){
    pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
  }

202149
202150
202151
202152
202153
202154
202155
202156
202157
202158
202159
202160
202161
202162
202163
){
  int i;
  const char *zSep = "";
  int rc = SQLITE_OK;
  SessionBuffer buf = {0, 0, 0};
  int nPk = 0;

  sessionAppendStr(&buf, "DELETE FROM ", &rc);
  sessionAppendIdent(&buf, zTab, &rc);
  sessionAppendStr(&buf, " WHERE ", &rc);

  for(i=0; i<p->nCol; i++){
    if( p->abPK[i] ){
      nPk++;
      sessionAppendStr(&buf, zSep, &rc);







|







204130
204131
204132
204133
204134
204135
204136
204137
204138
204139
204140
204141
204142
204143
204144
){
  int i;
  const char *zSep = "";
  int rc = SQLITE_OK;
  SessionBuffer buf = {0, 0, 0};
  int nPk = 0;

  sessionAppendStr(&buf, "DELETE FROM main.", &rc);
  sessionAppendIdent(&buf, zTab, &rc);
  sessionAppendStr(&buf, " WHERE ", &rc);

  for(i=0; i<p->nCol; i++){
    if( p->abPK[i] ){
      nPk++;
      sessionAppendStr(&buf, zSep, &rc);
202232
202233
202234
202235
202236
202237
202238
202239
202240
202241
202242
202243
202244
202245
202246
){
  int rc = SQLITE_OK;
  int i;
  const char *zSep = "";
  SessionBuffer buf = {0, 0, 0};

  /* Append "UPDATE tbl SET " */
  sessionAppendStr(&buf, "UPDATE ", &rc);
  sessionAppendIdent(&buf, zTab, &rc);
  sessionAppendStr(&buf, " SET ", &rc);

  /* Append the assignments */
  for(i=0; i<p->nCol; i++){
    sessionAppendStr(&buf, zSep, &rc);
    sessionAppendIdent(&buf, p->azCol[i], &rc);







|







204213
204214
204215
204216
204217
204218
204219
204220
204221
204222
204223
204224
204225
204226
204227
){
  int rc = SQLITE_OK;
  int i;
  const char *zSep = "";
  SessionBuffer buf = {0, 0, 0};

  /* Append "UPDATE tbl SET " */
  sessionAppendStr(&buf, "UPDATE main.", &rc);
  sessionAppendIdent(&buf, zTab, &rc);
  sessionAppendStr(&buf, " SET ", &rc);

  /* Append the assignments */
  for(i=0; i<p->nCol; i++){
    sessionAppendStr(&buf, zSep, &rc);
    sessionAppendIdent(&buf, p->azCol[i], &rc);
204279
204280
204281
204282
204283
204284
204285
204286
204287
204288
204289
204290
204291
204292
204293
**   If the query runs to completion without incident, SQLITE_OK is returned.
**   Or, if some error occurs before the query completes or is aborted by
**   the callback, an SQLite error code is returned.
**
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
**   Save the pointer passed as the second argument as the extension functions 
**   "auxiliary data". The pointer may then be retrieved by the current or any
**   future invocation of the same fts5 extension function made as part of
**   the same MATCH query using the xGetAuxdata() API.
**
**   Each extension function is allocated a single auxiliary data slot for
**   each FTS query (MATCH expression). If the extension function is invoked 
**   more than once for a single FTS query, then all invocations share a 







|







206260
206261
206262
206263
206264
206265
206266
206267
206268
206269
206270
206271
206272
206273
206274
**   If the query runs to completion without incident, SQLITE_OK is returned.
**   Or, if some error occurs before the query completes or is aborted by
**   the callback, an SQLite error code is returned.
**
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
**   Save the pointer passed as the second argument as the extension function's 
**   "auxiliary data". The pointer may then be retrieved by the current or any
**   future invocation of the same fts5 extension function made as part of
**   the same MATCH query using the xGetAuxdata() API.
**
**   Each extension function is allocated a single auxiliary data slot for
**   each FTS query (MATCH expression). If the extension function is invoked 
**   more than once for a single FTS query, then all invocations share a 
204521
204522
204523
204524
204525
204526
204527
204528
204529
204530
204531
204532
204533
204534
204535
204536
**   of "first place" within the document set, but not alternative forms
**   such as "1st place". In some applications, it would be better to match
**   all instances of "first place" or "1st place" regardless of which form
**   the user specified in the MATCH query text.
**
**   There are several ways to approach this in FTS5:
**
**   <ol><li> By mapping all synonyms to a single token. In this case, the 
**            In the above example, this means that the tokenizer returns the
**            same token for inputs "first" and "1st". Say that token is in
**            fact "first", so that when the user inserts the document "I won
**            1st place" entries are added to the index for tokens "i", "won",
**            "first" and "place". If the user then queries for '1st + place',
**            the tokenizer substitutes "first" for "1st" and the query works
**            as expected.
**







|
|







206502
206503
206504
206505
206506
206507
206508
206509
206510
206511
206512
206513
206514
206515
206516
206517
**   of "first place" within the document set, but not alternative forms
**   such as "1st place". In some applications, it would be better to match
**   all instances of "first place" or "1st place" regardless of which form
**   the user specified in the MATCH query text.
**
**   There are several ways to approach this in FTS5:
**
**   <ol><li> By mapping all synonyms to a single token. In this case, using
**            the above example, this means that the tokenizer returns the
**            same token for inputs "first" and "1st". Say that token is in
**            fact "first", so that when the user inserts the document "I won
**            1st place" entries are added to the index for tokens "i", "won",
**            "first" and "place". If the user then queries for '1st + place',
**            the tokenizer substitutes "first" for "1st" and the query works
**            as expected.
**
205683
205684
205685
205686
205687
205688
205689

205690
205691
205692
205693
205694
205695
205696
#define sqlite3Fts5ParserCTX_SDECL
#define sqlite3Fts5ParserCTX_PDECL
#define sqlite3Fts5ParserCTX_PARAM
#define sqlite3Fts5ParserCTX_FETCH
#define sqlite3Fts5ParserCTX_STORE
#define fts5YYNSTATE             35
#define fts5YYNRULE              28

#define fts5YYNFTS5TOKEN             16
#define fts5YY_MAX_SHIFT         34
#define fts5YY_MIN_SHIFTREDUCE   52
#define fts5YY_MAX_SHIFTREDUCE   79
#define fts5YY_ERROR_ACTION      80
#define fts5YY_ACCEPT_ACTION     81
#define fts5YY_NO_ACTION         82







>







207664
207665
207666
207667
207668
207669
207670
207671
207672
207673
207674
207675
207676
207677
207678
#define sqlite3Fts5ParserCTX_SDECL
#define sqlite3Fts5ParserCTX_PDECL
#define sqlite3Fts5ParserCTX_PARAM
#define sqlite3Fts5ParserCTX_FETCH
#define sqlite3Fts5ParserCTX_STORE
#define fts5YYNSTATE             35
#define fts5YYNRULE              28
#define fts5YYNRULE_WITH_ACTION  28
#define fts5YYNFTS5TOKEN             16
#define fts5YY_MAX_SHIFT         34
#define fts5YY_MIN_SHIFTREDUCE   52
#define fts5YY_MAX_SHIFTREDUCE   79
#define fts5YY_ERROR_ACTION      80
#define fts5YY_ACCEPT_ACTION     81
#define fts5YY_NO_ACTION         82
206512
206513
206514
206515
206516
206517
206518
206519
206520
206521


206522
206523
206524

206525
206526
206527
206528
206529
206530
206531
  (void)fts5yyLookahead;
  (void)fts5yyLookaheadToken;
  fts5yymsp = fts5yypParser->fts5yytos;
#ifndef NDEBUG
  if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
    fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno];
    if( fts5yysize ){
      fprintf(fts5yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
        fts5yyTracePrompt,
        fts5yyruleno, fts5yyRuleName[fts5yyruleno], fts5yymsp[fts5yysize].stateno);


    }else{
      fprintf(fts5yyTraceFILE, "%sReduce %d [%s].\n",
        fts5yyTracePrompt, fts5yyruleno, fts5yyRuleName[fts5yyruleno]);

    }
  }
#endif /* NDEBUG */

  /* Check that the stack is large enough to grow by a single entry
  ** if the RHS of the rule is empty.  This ensures that there is room
  ** enough on the stack to push the LHS value */







|

|
>
>

|
|
>







208494
208495
208496
208497
208498
208499
208500
208501
208502
208503
208504
208505
208506
208507
208508
208509
208510
208511
208512
208513
208514
208515
208516
  (void)fts5yyLookahead;
  (void)fts5yyLookaheadToken;
  fts5yymsp = fts5yypParser->fts5yytos;
#ifndef NDEBUG
  if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
    fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno];
    if( fts5yysize ){
      fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
        fts5yyTracePrompt,
        fts5yyruleno, fts5yyRuleName[fts5yyruleno],
        fts5yyruleno<fts5YYNRULE_WITH_ACTION ? "" : " without external action",
        fts5yymsp[fts5yysize].stateno);
    }else{
      fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s.\n",
        fts5yyTracePrompt, fts5yyruleno, fts5yyRuleName[fts5yyruleno],
        fts5yyruleno<fts5YYNRULE_WITH_ACTION ? "" : " without external action");
    }
  }
#endif /* NDEBUG */

  /* Check that the stack is large enough to grow by a single entry
  ** if the RHS of the rule is empty.  This ensures that there is room
  ** enough on the stack to push the LHS value */
208276
208277
208278
208279
208280
208281
208282
208283
208284
208285
208286
208287
208288
208289
208290
  int iOut = 0;
  q = z[0];

  /* Set stack variable q to the close-quote character */
  assert( q=='[' || q=='\'' || q=='"' || q=='`' );
  if( q=='[' ) q = ']';  

  while( ALWAYS(z[iIn]) ){
    if( z[iIn]==q ){
      if( z[iIn+1]!=q ){
        /* Character iIn was the close quote. */
        iIn++;
        break;
      }else{
        /* Character iIn and iIn+1 form an escaped quote character. Skip







|







210261
210262
210263
210264
210265
210266
210267
210268
210269
210270
210271
210272
210273
210274
210275
  int iOut = 0;
  q = z[0];

  /* Set stack variable q to the close-quote character */
  assert( q=='[' || q=='\'' || q=='"' || q=='`' );
  if( q=='[' ) q = ']';  

  while( z[iIn] ){
    if( z[iIn]==q ){
      if( z[iIn+1]!=q ){
        /* Character iIn was the close quote. */
        iIn++;
        break;
      }else{
        /* Character iIn and iIn+1 form an escaped quote character. Skip
211605
211606
211607
211608
211609
211610
211611
211612

211613
211614
211615

211616
211617
211618
211619
211620
211621
211622
    sqlite3_result_error_nomem(pCtx);
    return;
  }
  azConfig[0] = 0;
  azConfig[1] = "main";
  azConfig[2] = "tbl";
  for(i=3; iArg<nArg; iArg++){
    azConfig[i++] = (const char*)sqlite3_value_text(apVal[iArg]);

  }

  zExpr = (const char*)sqlite3_value_text(apVal[0]);


  rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
  if( rc==SQLITE_OK ){
    rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
  }
  if( rc==SQLITE_OK ){
    char *zText;







|
>



>







213590
213591
213592
213593
213594
213595
213596
213597
213598
213599
213600
213601
213602
213603
213604
213605
213606
213607
213608
213609
    sqlite3_result_error_nomem(pCtx);
    return;
  }
  azConfig[0] = 0;
  azConfig[1] = "main";
  azConfig[2] = "tbl";
  for(i=3; iArg<nArg; iArg++){
    const char *z = (const char*)sqlite3_value_text(apVal[iArg]);
    azConfig[i++] = (z ? z : "");
  }

  zExpr = (const char*)sqlite3_value_text(apVal[0]);
  if( zExpr==0 ) zExpr = "";

  rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
  if( rc==SQLITE_OK ){
    rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
  }
  if( rc==SQLITE_OK ){
    char *zText;
217858
217859
217860
217861
217862
217863
217864
217865
217866
217867
217868



217869
217870
217871
217872
217873
217874
217875
  int nChar
){
  int n = 0;
  int i;
  for(i=0; i<nChar; i++){
    if( n>=nByte ) return 0;      /* Input contains fewer than nChar chars */
    if( (unsigned char)p[n++]>=0xc0 ){
      if( n>=nByte ) break;
      while( (p[n] & 0xc0)==0x80 ){
        n++;
        if( n>=nByte ) break;



      }
    }
  }
  return n;
}

/*







|


|
>
>
>







219845
219846
219847
219848
219849
219850
219851
219852
219853
219854
219855
219856
219857
219858
219859
219860
219861
219862
219863
219864
219865
  int nChar
){
  int n = 0;
  int i;
  for(i=0; i<nChar; i++){
    if( n>=nByte ) return 0;      /* Input contains fewer than nChar chars */
    if( (unsigned char)p[n++]>=0xc0 ){
      if( n>=nByte ) return 0;
      while( (p[n] & 0xc0)==0x80 ){
        n++;
        if( n>=nByte ){
          if( i+1==nChar ) break;
          return 0;
        }
      }
    }
  }
  return n;
}

/*
218263
218264
218265
218266
218267
218268
218269































218270
218271
218272
218273
218274
218275
218276
  }
  sqlite3Fts5IterClose(pIter);

  *pCksum = cksum;
  return rc;
}

































/*
** This function is also purely an internal test. It does not contribute to 
** FTS functionality, or even the integrity-check, in any way.
*/
static void fts5TestTerm(
  Fts5Index *p, 







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







220253
220254
220255
220256
220257
220258
220259
220260
220261
220262
220263
220264
220265
220266
220267
220268
220269
220270
220271
220272
220273
220274
220275
220276
220277
220278
220279
220280
220281
220282
220283
220284
220285
220286
220287
220288
220289
220290
220291
220292
220293
220294
220295
220296
220297
  }
  sqlite3Fts5IterClose(pIter);

  *pCksum = cksum;
  return rc;
}

/*
** Check if buffer z[], size n bytes, contains as series of valid utf-8
** encoded codepoints. If so, return 0. Otherwise, if the buffer does not
** contain valid utf-8, return non-zero.
*/
static int fts5TestUtf8(const char *z, int n){
  int i = 0;
  assert_nc( n>0 );
  while( i<n ){
    if( (z[i] & 0x80)==0x00 ){
      i++;
    }else
    if( (z[i] & 0xE0)==0xC0 ){
      if( i+1>=n || (z[i+1] & 0xC0)!=0x80 ) return 1;
      i += 2;
    }else
    if( (z[i] & 0xF0)==0xE0 ){
      if( i+2>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
      i += 3;
    }else
    if( (z[i] & 0xF8)==0xF0 ){
      if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
      if( (z[i+2] & 0xC0)!=0x80 ) return 1;
      i += 3;
    }else{
      return 1;
    }
  }

  return 0;
}

/*
** This function is also purely an internal test. It does not contribute to 
** FTS functionality, or even the integrity-check, in any way.
*/
static void fts5TestTerm(
  Fts5Index *p, 
218303
218304
218305
218306
218307
218308
218309
218310






218311
218312
218313
218314
218315
218316
218317
218318

    /* If this is a prefix query, check that the results returned if the
    ** the index is disabled are the same. In both ASC and DESC order. 
    **
    ** This check may only be performed if the hash table is empty. This
    ** is because the hash table only supports a single scan query at
    ** a time, and the multi-iter loop from which this function is called
    ** is already performing such a scan. */






    if( p->nPendingData==0 ){
      if( iIdx>0 && rc==SQLITE_OK ){
        int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
        ck2 = 0;
        rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2);
        if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
      }
      if( iIdx>0 && rc==SQLITE_OK ){







|
>
>
>
>
>
>
|







220324
220325
220326
220327
220328
220329
220330
220331
220332
220333
220334
220335
220336
220337
220338
220339
220340
220341
220342
220343
220344
220345

    /* If this is a prefix query, check that the results returned if the
    ** the index is disabled are the same. In both ASC and DESC order. 
    **
    ** This check may only be performed if the hash table is empty. This
    ** is because the hash table only supports a single scan query at
    ** a time, and the multi-iter loop from which this function is called
    ** is already performing such a scan. 
    **
    ** Also only do this if buffer zTerm contains nTerm bytes of valid
    ** utf-8. Otherwise, the last part of the buffer contents might contain
    ** a non-utf-8 sequence that happens to be a prefix of a valid utf-8
    ** character stored in the main fts index, which will cause the
    ** test to fail.  */
    if( p->nPendingData==0 && 0==fts5TestUtf8(zTerm, nTerm) ){
      if( iIdx>0 && rc==SQLITE_OK ){
        int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
        ck2 = 0;
        rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2);
        if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
      }
      if( iIdx>0 && rc==SQLITE_OK ){
218437
218438
218439
218440
218441
218442
218443

218444
218445
218446
218447
218448
218449
218450
218451
218452
  ));

  /* Iterate through the b-tree hierarchy.  */
  while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    i64 iRow;                     /* Rowid for this leaf */
    Fts5Data *pLeaf;              /* Data for this leaf */


    int nIdxTerm = sqlite3_column_bytes(pStmt, 1);
    const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1);
    int iIdxLeaf = sqlite3_column_int(pStmt, 2);
    int bIdxDlidx = sqlite3_column_int(pStmt, 3);

    /* If the leaf in question has already been trimmed from the segment, 
    ** ignore this b-tree entry. Otherwise, load it into memory. */
    if( iIdxLeaf<pSeg->pgnoFirst ) continue;
    iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf);







>

<







220464
220465
220466
220467
220468
220469
220470
220471
220472

220473
220474
220475
220476
220477
220478
220479
  ));

  /* Iterate through the b-tree hierarchy.  */
  while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    i64 iRow;                     /* Rowid for this leaf */
    Fts5Data *pLeaf;              /* Data for this leaf */

    const char *zIdxTerm = (const char*)sqlite3_column_blob(pStmt, 1);
    int nIdxTerm = sqlite3_column_bytes(pStmt, 1);

    int iIdxLeaf = sqlite3_column_int(pStmt, 2);
    int bIdxDlidx = sqlite3_column_int(pStmt, 3);

    /* If the leaf in question has already been trimmed from the segment, 
    ** ignore this b-tree entry. Otherwise, load it into memory. */
    if( iIdxLeaf<pSeg->pgnoFirst ) continue;
    iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf);
219419
219420
219421
219422
219423
219424
219425



219426
219427
219428
219429
219430
219431
219432
219433
      assert( iSavepoint<=p->ts.iSavepoint );
      p->ts.iSavepoint = iSavepoint-1;
      break;

    case FTS5_ROLLBACKTO:
      assert( p->ts.eState==1 );
      assert( iSavepoint>=-1 );



      assert( iSavepoint<=p->ts.iSavepoint );
      p->ts.iSavepoint = iSavepoint;
      break;
  }
}
#else
# define fts5CheckTransactionState(x,y,z)
#endif







>
>
>
|







221446
221447
221448
221449
221450
221451
221452
221453
221454
221455
221456
221457
221458
221459
221460
221461
221462
221463
      assert( iSavepoint<=p->ts.iSavepoint );
      p->ts.iSavepoint = iSavepoint-1;
      break;

    case FTS5_ROLLBACKTO:
      assert( p->ts.eState==1 );
      assert( iSavepoint>=-1 );
      /* The following assert() can fail if another vtab strikes an error
      ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
      ** having called xSavepoint() on this vtab.  */
      /* assert( iSavepoint<=p->ts.iSavepoint ); */
      p->ts.iSavepoint = iSavepoint;
      break;
  }
}
#else
# define fts5CheckTransactionState(x,y,z)
#endif
220025
220026
220027
220028
220029
220030
220031
220032


220033

220034
220035
220036





220037
220038
220039
220040

220041
220042
220043
220044
220045
220046
220047
      }
  
      case FTS5_PLAN_SORTED_MATCH: {
        rc = fts5SorterNext(pCsr);
        break;
      }
  
      default:


        rc = sqlite3_step(pCsr->pStmt);

        if( rc!=SQLITE_ROW ){
          CsrFlagSet(pCsr, FTS5CSR_EOF);
          rc = sqlite3_reset(pCsr->pStmt);





        }else{
          rc = SQLITE_OK;
        }
        break;

    }
  }
  
  return rc;
}









|
>
>

>



>
>
>
>
>




>







222055
222056
222057
222058
222059
222060
222061
222062
222063
222064
222065
222066
222067
222068
222069
222070
222071
222072
222073
222074
222075
222076
222077
222078
222079
222080
222081
222082
222083
222084
222085
222086
      }
  
      case FTS5_PLAN_SORTED_MATCH: {
        rc = fts5SorterNext(pCsr);
        break;
      }
  
      default: {
        Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig;
        pConfig->bLock++;
        rc = sqlite3_step(pCsr->pStmt);
        pConfig->bLock--;
        if( rc!=SQLITE_ROW ){
          CsrFlagSet(pCsr, FTS5CSR_EOF);
          rc = sqlite3_reset(pCsr->pStmt);
          if( rc!=SQLITE_OK ){
            pCursor->pVtab->zErrMsg = sqlite3_mprintf(
                "%s", sqlite3_errmsg(pConfig->db)
            );
          }
        }else{
          rc = SQLITE_OK;
        }
        break;
      }
    }
  }
  
  return rc;
}


220317
220318
220319
220320
220321
220322
220323







220324
220325
220326
220327
220328
220329
220330
  sqlite3_value *pRowidLe = 0;    /* rowid <= ? expression (or NULL) */
  sqlite3_value *pRowidGe = 0;    /* rowid >= ? expression (or NULL) */
  int iCol;                       /* Column on LHS of MATCH operator */
  char **pzErrmsg = pConfig->pzErrmsg;
  int i;
  int iIdxStr = 0;
  Fts5Expr *pExpr = 0;








  if( pCsr->ePlan ){
    fts5FreeCursorComponents(pCsr);
    memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
  }

  assert( pCsr->pStmt==0 );







>
>
>
>
>
>
>







222356
222357
222358
222359
222360
222361
222362
222363
222364
222365
222366
222367
222368
222369
222370
222371
222372
222373
222374
222375
222376
  sqlite3_value *pRowidLe = 0;    /* rowid <= ? expression (or NULL) */
  sqlite3_value *pRowidGe = 0;    /* rowid >= ? expression (or NULL) */
  int iCol;                       /* Column on LHS of MATCH operator */
  char **pzErrmsg = pConfig->pzErrmsg;
  int i;
  int iIdxStr = 0;
  Fts5Expr *pExpr = 0;

  if( pConfig->bLock ){
    pTab->p.base.zErrMsg = sqlite3_mprintf(
        "recursively defined fts5 content table"
    );
    return SQLITE_ERROR;
  }

  if( pCsr->ePlan ){
    fts5FreeCursorComponents(pCsr);
    memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
  }

  assert( pCsr->pStmt==0 );
220538
220539
220540
220541
220542
220543
220544

220545
220546
220547

220548

220549
220550
220551
220552
220553
220554
220555




220556
220557
220558
220559
220560
220561
220562
        pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0)
    );
    assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 );
    assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
  }

  if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){

    assert( pCsr->pExpr );
    sqlite3_reset(pCsr->pStmt);
    sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));

    rc = sqlite3_step(pCsr->pStmt);

    if( rc==SQLITE_ROW ){
      rc = SQLITE_OK;
      CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
    }else{
      rc = sqlite3_reset(pCsr->pStmt);
      if( rc==SQLITE_OK ){
        rc = FTS5_CORRUPT;




      }
    }
  }
  return rc;
}

static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){







>



>

>







>
>
>
>







222584
222585
222586
222587
222588
222589
222590
222591
222592
222593
222594
222595
222596
222597
222598
222599
222600
222601
222602
222603
222604
222605
222606
222607
222608
222609
222610
222611
222612
222613
222614
222615
        pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0)
    );
    assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 );
    assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
  }

  if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
    Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
    assert( pCsr->pExpr );
    sqlite3_reset(pCsr->pStmt);
    sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
    pTab->pConfig->bLock++;
    rc = sqlite3_step(pCsr->pStmt);
    pTab->pConfig->bLock--;
    if( rc==SQLITE_ROW ){
      rc = SQLITE_OK;
      CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
    }else{
      rc = sqlite3_reset(pCsr->pStmt);
      if( rc==SQLITE_OK ){
        rc = FTS5_CORRUPT;
      }else if( pTab->pConfig->pzErrmsg ){
        *pTab->pConfig->pzErrmsg = sqlite3_mprintf(
            "%s", sqlite3_errmsg(pTab->pConfig->db)
        );
      }
    }
  }
  return rc;
}

static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
221564
221565
221566
221567
221568
221569
221570

221571
221572
221573
221574

221575
221576
221577
221578
221579
221580
221581
     || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
    ){
      if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
        fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
      }
    }
  }else if( !fts5IsContentless(pTab) ){

    rc = fts5SeekCursor(pCsr, 1);
    if( rc==SQLITE_OK ){
      sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
    }

  }
  return rc;
}


/*
** This routine implements the xFindFunction method for the FTS3







>




>







223617
223618
223619
223620
223621
223622
223623
223624
223625
223626
223627
223628
223629
223630
223631
223632
223633
223634
223635
223636
     || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
    ){
      if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
        fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
      }
    }
  }else if( !fts5IsContentless(pTab) ){
    pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
    rc = fts5SeekCursor(pCsr, 1);
    if( rc==SQLITE_OK ){
      sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
    }
    pConfig->pzErrmsg = 0;
  }
  return rc;
}


/*
** This routine implements the xFindFunction method for the FTS3
221844
221845
221846
221847
221848
221849
221850
221851
221852
221853
221854
221855
221856
221857
221858
static void fts5SourceIdFunc(
  sqlite3_context *pCtx,          /* Function call context */
  int nArg,                       /* Number of args */
  sqlite3_value **apUnused        /* Function arguments */
){
  assert( nArg==0 );
  UNUSED_PARAM2(nArg, apUnused);
  sqlite3_result_text(pCtx, "fts5: 2019-11-20 12:07:40 2575a68c3965e72f2ab211d933012442755afe6a9b7de9e9e50cdd2155fd1ec8", -1, SQLITE_TRANSIENT);
}

/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int fts5ShadowName(const char *zName){







|







223899
223900
223901
223902
223903
223904
223905
223906
223907
223908
223909
223910
223911
223912
223913
static void fts5SourceIdFunc(
  sqlite3_context *pCtx,          /* Function call context */
  int nArg,                       /* Number of args */
  sqlite3_value **apUnused        /* Function arguments */
){
  assert( nArg==0 );
  UNUSED_PARAM2(nArg, apUnused);
  sqlite3_result_text(pCtx, "fts5: 2020-03-03 20:04:29 bd94d7d052734460904c687756231f8aa243a2252f07f742dd1e437aa940f536", -1, SQLITE_TRANSIENT);
}

/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int fts5ShadowName(const char *zName){
222591
222592
222593
222594
222595
222596
222597


222598
222599
222600
222601

222602
222603
222604
222605
222606
222607
222608
    i64 iRowid = sqlite3_column_int64(pScan, 0);

    sqlite3Fts5BufferZero(&buf);
    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
    for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
      ctx.szCol = 0;
      if( pConfig->abUnindexed[ctx.iCol]==0 ){


        rc = sqlite3Fts5Tokenize(pConfig, 
            FTS5_TOKENIZE_DOCUMENT,
            (const char*)sqlite3_column_text(pScan, ctx.iCol+1),
            sqlite3_column_bytes(pScan, ctx.iCol+1),

            (void*)&ctx,
            fts5StorageInsertCallback
        );
      }
      sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
      p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
    }







>
>


<
<
>







224646
224647
224648
224649
224650
224651
224652
224653
224654
224655
224656


224657
224658
224659
224660
224661
224662
224663
224664
    i64 iRowid = sqlite3_column_int64(pScan, 0);

    sqlite3Fts5BufferZero(&buf);
    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
    for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
      ctx.szCol = 0;
      if( pConfig->abUnindexed[ctx.iCol]==0 ){
        const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
        int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
        rc = sqlite3Fts5Tokenize(pConfig, 
            FTS5_TOKENIZE_DOCUMENT,


            zText, nText,
            (void*)&ctx,
            fts5StorageInsertCallback
        );
      }
      sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
      p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
    }
222716
222717
222718
222719
222720
222721
222722


222723
222724
222725
222726

222727
222728
222729
222730
222731
222732
222733

  if( rc==SQLITE_OK ){
    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
  }
  for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
    ctx.szCol = 0;
    if( pConfig->abUnindexed[ctx.iCol]==0 ){


      rc = sqlite3Fts5Tokenize(pConfig, 
          FTS5_TOKENIZE_DOCUMENT,
          (const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
          sqlite3_value_bytes(apVal[ctx.iCol+2]),

          (void*)&ctx,
          fts5StorageInsertCallback
      );
    }
    sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
    p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
  }







>
>


<
<
>







224772
224773
224774
224775
224776
224777
224778
224779
224780
224781
224782


224783
224784
224785
224786
224787
224788
224789
224790

  if( rc==SQLITE_OK ){
    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
  }
  for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
    ctx.szCol = 0;
    if( pConfig->abUnindexed[ctx.iCol]==0 ){
      const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
      int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
      rc = sqlite3Fts5Tokenize(pConfig, 
          FTS5_TOKENIZE_DOCUMENT,


          zText, nText,
          (void*)&ctx,
          fts5StorageInsertCallback
      );
    }
    sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
    p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
  }
222888
222889
222890
222891
222892
222893
222894


222895
222896
222897
222898
222899
222900
222901
222902
222903
222904
222905
        if( pConfig->abUnindexed[i] ) continue;
        ctx.iCol = i;
        ctx.szCol = 0;
        if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
          rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
        }
        if( rc==SQLITE_OK ){


          rc = sqlite3Fts5Tokenize(pConfig, 
              FTS5_TOKENIZE_DOCUMENT,
              (const char*)sqlite3_column_text(pScan, i+1),
              sqlite3_column_bytes(pScan, i+1),
              (void*)&ctx,
              fts5StorageIntegrityCallback
          );
        }
        if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
          rc = FTS5_CORRUPT;
        }







>
>


|
<







224945
224946
224947
224948
224949
224950
224951
224952
224953
224954
224955
224956

224957
224958
224959
224960
224961
224962
224963
        if( pConfig->abUnindexed[i] ) continue;
        ctx.iCol = i;
        ctx.szCol = 0;
        if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
          rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
        }
        if( rc==SQLITE_OK ){
          const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
          int nText = sqlite3_column_bytes(pScan, i+1);
          rc = sqlite3Fts5Tokenize(pConfig, 
              FTS5_TOKENIZE_DOCUMENT,
              zText, nText,

              (void*)&ctx,
              fts5StorageIntegrityCallback
          );
        }
        if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
          rc = FTS5_CORRUPT;
        }
225584
225585
225586
225587
225588
225589
225590

225591
225592
225593
225594
225595
225596
225597
struct Fts5VocabTable {
  sqlite3_vtab base;
  char *zFts5Tbl;                 /* Name of fts5 table */
  char *zFts5Db;                  /* Db containing fts5 table */
  sqlite3 *db;                    /* Database handle */
  Fts5Global *pGlobal;            /* FTS5 global object for this database */
  int eType;                      /* FTS5_VOCAB_COL, ROW or INSTANCE */

};

struct Fts5VocabCursor {
  sqlite3_vtab_cursor base;
  sqlite3_stmt *pStmt;            /* Statement holding lock on pIndex */
  Fts5Table *pFts5;               /* Associated FTS5 table */








>







227642
227643
227644
227645
227646
227647
227648
227649
227650
227651
227652
227653
227654
227655
227656
struct Fts5VocabTable {
  sqlite3_vtab base;
  char *zFts5Tbl;                 /* Name of fts5 table */
  char *zFts5Db;                  /* Db containing fts5 table */
  sqlite3 *db;                    /* Database handle */
  Fts5Global *pGlobal;            /* FTS5 global object for this database */
  int eType;                      /* FTS5_VOCAB_COL, ROW or INSTANCE */
  unsigned bBusy;                 /* True if busy */
};

struct Fts5VocabCursor {
  sqlite3_vtab_cursor base;
  sqlite3_stmt *pStmt;            /* Statement holding lock on pIndex */
  Fts5Table *pFts5;               /* Associated FTS5 table */

225866
225867
225868
225869
225870
225871
225872






225873
225874
225875
225876
225877
225878
225879
225880
225881
225882
225883

225884
225885
225886
225887

225888
225889
225890
225891
225892
225893
225894
  Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
  Fts5Table *pFts5 = 0;
  Fts5VocabCursor *pCsr = 0;
  int rc = SQLITE_OK;
  sqlite3_stmt *pStmt = 0;
  char *zSql = 0;







  zSql = sqlite3Fts5Mprintf(&rc,
      "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
      pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
  );
  if( zSql ){
    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
  }
  sqlite3_free(zSql);
  assert( rc==SQLITE_OK || pStmt==0 );
  if( rc==SQLITE_ERROR ) rc = SQLITE_OK;


  if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
    i64 iId = sqlite3_column_int64(pStmt, 0);
    pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId);
  }


  if( rc==SQLITE_OK ){
    if( pFts5==0 ){
      rc = sqlite3_finalize(pStmt);
      pStmt = 0;
      if( rc==SQLITE_OK ){
        pVTab->zErrMsg = sqlite3_mprintf(







>
>
>
>
>
>











>




>







227925
227926
227927
227928
227929
227930
227931
227932
227933
227934
227935
227936
227937
227938
227939
227940
227941
227942
227943
227944
227945
227946
227947
227948
227949
227950
227951
227952
227953
227954
227955
227956
227957
227958
227959
227960
227961
  Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
  Fts5Table *pFts5 = 0;
  Fts5VocabCursor *pCsr = 0;
  int rc = SQLITE_OK;
  sqlite3_stmt *pStmt = 0;
  char *zSql = 0;

  if( pTab->bBusy ){
    pVTab->zErrMsg = sqlite3_mprintf(
       "recursive definition for %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
    );
    return SQLITE_ERROR;
  }
  zSql = sqlite3Fts5Mprintf(&rc,
      "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
      pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
  );
  if( zSql ){
    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
  }
  sqlite3_free(zSql);
  assert( rc==SQLITE_OK || pStmt==0 );
  if( rc==SQLITE_ERROR ) rc = SQLITE_OK;

  pTab->bBusy = 1;
  if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
    i64 iId = sqlite3_column_int64(pStmt, 0);
    pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId);
  }
  pTab->bBusy = 0;

  if( rc==SQLITE_OK ){
    if( pFts5==0 ){
      rc = sqlite3_finalize(pStmt);
      pStmt = 0;
      if( rc==SQLITE_OK ){
        pVTab->zErrMsg = sqlite3_mprintf(
226614
226615
226616
226617
226618
226619
226620
226621
226622
226623
226624
226625
226626
226627
#endif
  return rc;
}
#endif /* SQLITE_CORE */
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */

/************** End of stmt.c ************************************************/
#if __LINE__!=226621
#undef SQLITE_SOURCE_ID
#define SQLITE_SOURCE_ID      "2019-11-20 13:31:52 a0f6d526baecd061a5e2bec5eb698fb5dfb10122ac79c853d7b3f4a48bc9alt2"
#endif
/* Return the source-id for this library */
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
/************************** End of sqlite3.c ******************************/







|

|




228681
228682
228683
228684
228685
228686
228687
228688
228689
228690
228691
228692
228693
228694
#endif
  return rc;
}
#endif /* SQLITE_CORE */
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */

/************** End of stmt.c ************************************************/
#if __LINE__!=228688
#undef SQLITE_SOURCE_ID
#define SQLITE_SOURCE_ID      "2020-04-20 17:35:32 2fc80ef16ce5878311ab88a0c64631813572ffbb71f75363b4619c9667e0alt2"
#endif
/* Return the source-id for this library */
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
/************************** End of sqlite3.c ******************************/
Changes to src/sqlite3.h.
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
** been edited in any way since it was last checked in, then the last
** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.31.0"
#define SQLITE_VERSION_NUMBER 3031000
#define SQLITE_SOURCE_ID      "2019-11-20 13:31:52 a0f6d526baecd061a5e2bec5eb698fb5dfb10122ac79c853d7b3f4a48bc9f49b"

/*
** 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







|
|
|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
** been edited in any way since it was last checked in, then the last
** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.32.0"
#define SQLITE_VERSION_NUMBER 3032000
#define SQLITE_SOURCE_ID      "2020-04-20 17:35:32 2fc80ef16ce5878311ab88a0c64631813572ffbb71f75363b4619c9667e0926b"

/*
** 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
532
533
534
535
536
537
538

539
540
541
542
543

544
545
546
547
548
549
550
#define SQLITE_CONSTRAINT_FUNCTION     (SQLITE_CONSTRAINT | (4<<8))
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))

#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))


/*
** CAPI3REF: Flags For File Open Operations
**
** These bit values are intended for use in the
** 3rd parameter to the [sqlite3_open_v2()] interface and
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.







>





>







532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
#define SQLITE_CONSTRAINT_FUNCTION     (SQLITE_CONSTRAINT | (4<<8))
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))
#define SQLITE_CONSTRAINT_PINNED       (SQLITE_CONSTRAINT |(11<<8))
#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK              (SQLITE_OK | (2<<8))

/*
** CAPI3REF: Flags For File Open Operations
**
** These bit values are intended for use in the
** 3rd parameter to the [sqlite3_open_v2()] interface and
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
** file control occurs at the beginning of pragma statement analysis and so
** it is able to override built-in [PRAGMA] statements.
**
** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
** to the connections busy-handler callback. The argument is of type (void **)
** - an array of two (void *) values. The first (void *) actually points
** to a function of type (int (*)(void *)). In order to invoke the connections
** busy-handler, this function should be invoked with the second (void *) in
** the array as the only argument. If it returns non-zero, then the operation
** should be retried. If it returns zero, the custom VFS should abandon the
** current operation.
**
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses.  The
** argument should be a char** which will be filled with the filename
** written into memory obtained from [sqlite3_malloc()].  The caller should
** invoke [sqlite3_free()] on the result to avoid a memory leak.
**







|

|






|







979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
** file control occurs at the beginning of pragma statement analysis and so
** it is able to override built-in [PRAGMA] statements.
**
** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
** to the connection's busy-handler callback. The argument is of type (void**)
** - an array of two (void *) values. The first (void *) actually points
** to a function of type (int (*)(void *)). In order to invoke the connection's
** busy-handler, this function should be invoked with the second (void *) in
** the array as the only argument. If it returns non-zero, then the operation
** should be retried. If it returns zero, the custom VFS should abandon the
** current operation.
**
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
** ^Applications can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses.  The
** argument should be a char** which will be filled with the filename
** written into memory obtained from [sqlite3_malloc()].  The caller should
** invoke [sqlite3_free()] on the result to avoid a memory leak.
**
1081
1082
1083
1084
1085
1086
1087
1088

1089
1090
1091


1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111






1112
1113
1114
1115
1116
1117
1118
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
** ^This file control takes the file descriptor out of batch write mode
** so that all subsequent write operations are independent.
** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
**
** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain

** a file lock using the xLock or xShmLock methods of the VFS to wait
** for up to M milliseconds before failing, where M is the single 
** unsigned integer parameter.


**
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
** a database file.  The argument is a pointer to a 32-bit unsigned integer.
** The "data version" for the pager is written into the pointer.  The
** "data version" changes whenever any change occurs to the corresponding
** database file, either through SQL statements on the same database
** connection or through transactions committed by separate database
** connections possibly in other processes. The [sqlite3_total_changes()]
** interface can be used to find if any database on the connection has changed,
** but that interface responds to changes on TEMP as well as MAIN and does
** not provide a mechanism to detect changes to MAIN only.  Also, the
** [sqlite3_total_changes()] interface responds to internal changes only and
** omits changes made by other database connections.  The
** [PRAGMA data_version] command provide a mechanism to detect changes to
** a single attached database that occur due to other database connections,
** but omits changes implemented by the database connection on which it is
** called.  This file control is the only mechanism to detect changes that
** happen either internally or externally and that are associated with
** a particular attached database.






** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE               1
#define SQLITE_FCNTL_GET_LOCKPROXYFILE       2
#define SQLITE_FCNTL_SET_LOCKPROXYFILE       3
#define SQLITE_FCNTL_LAST_ERRNO              4
#define SQLITE_FCNTL_SIZE_HINT               5







|
>
|
<
|
>
>














|





>
>
>
>
>
>







1083
1084
1085
1086
1087
1088
1089
1090
1091
1092

1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
** ^This file control takes the file descriptor out of batch write mode
** so that all subsequent write operations are independent.
** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
**
** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS
** to block for up to M milliseconds before failing when attempting to 
** obtain a file lock using the xLock or xShmLock methods of the VFS. 

** The parameter is a pointer to a 32-bit signed integer that contains
** the value that M is to be set to. Before returning, the 32-bit signed
** integer is overwritten with the previous value of M.
**
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
** a database file.  The argument is a pointer to a 32-bit unsigned integer.
** The "data version" for the pager is written into the pointer.  The
** "data version" changes whenever any change occurs to the corresponding
** database file, either through SQL statements on the same database
** connection or through transactions committed by separate database
** connections possibly in other processes. The [sqlite3_total_changes()]
** interface can be used to find if any database on the connection has changed,
** but that interface responds to changes on TEMP as well as MAIN and does
** not provide a mechanism to detect changes to MAIN only.  Also, the
** [sqlite3_total_changes()] interface responds to internal changes only and
** omits changes made by other database connections.  The
** [PRAGMA data_version] command provides a mechanism to detect changes to
** a single attached database that occur due to other database connections,
** but omits changes implemented by the database connection on which it is
** called.  This file control is the only mechanism to detect changes that
** happen either internally or externally and that are associated with
** a particular attached database.
**
** <li>[[SQLITE_FCNTL_CKPT_DONE]]
** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
** in wal mode after the client has finished copying pages from the wal
** file to the database file, but before the *-shm file is updated to
** record the fact that the pages have been checkpointed.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE               1
#define SQLITE_FCNTL_GET_LOCKPROXYFILE       2
#define SQLITE_FCNTL_SET_LOCKPROXYFILE       3
#define SQLITE_FCNTL_LAST_ERRNO              4
#define SQLITE_FCNTL_SIZE_HINT               5
1142
1143
1144
1145
1146
1147
1148


1149
1150
1151
1152
1153
1154
1155
#define SQLITE_FCNTL_PDB                    30
#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
#define SQLITE_FCNTL_LOCK_TIMEOUT           34
#define SQLITE_FCNTL_DATA_VERSION           35
#define SQLITE_FCNTL_SIZE_LIMIT             36



/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
#define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
#define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO









>
>







1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
#define SQLITE_FCNTL_PDB                    30
#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
#define SQLITE_FCNTL_LOCK_TIMEOUT           34
#define SQLITE_FCNTL_DATA_VERSION           35
#define SQLITE_FCNTL_SIZE_LIMIT             36
#define SQLITE_FCNTL_CKPT_DONE              37
#define SQLITE_FCNTL_RESERVE_BYTES          38

/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
#define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
#define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO


1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
** the end.  Each time such an extension occurs, the iVersion field
** is incremented.  The iVersion value started out as 1 in
** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6].  Additional fields
** may be appended to the sqlite3_vfs object and the iVersion value
** may increase again in future versions of SQLite.
** Note that the structure
** of the sqlite3_vfs object changes in the transition from
** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
** and yet the iVersion field was not modified.
**
** The szOsFile field is the size of the subclassed [sqlite3_file]
** structure used by this VFS.  mxPathname is the maximum length of
** a pathname in this VFS.
**
** Registered sqlite3_vfs objects are kept on a linked list formed by
** the pNext pointer.  The [sqlite3_vfs_register()]







|
|

|







1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
** the end.  Each time such an extension occurs, the iVersion field
** is incremented.  The iVersion value started out as 1 in
** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6].  Additional fields
** may be appended to the sqlite3_vfs object and the iVersion value
** may increase again in future versions of SQLite.
** Note that due to an oversight, the structure
** of the sqlite3_vfs object changed in the transition from
** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
** and yet the iVersion field was not increased.
**
** The szOsFile field is the size of the subclassed [sqlite3_file]
** structure used by this VFS.  mxPathname is the maximum length of
** a pathname in this VFS.
**
** Registered sqlite3_vfs objects are kept on a linked list formed by
** the pNext pointer.  The [sqlite3_vfs_register()]
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
** API.  The SQLITE_OPEN_EXCLUSIVE flag, when paired with the 
** SQLITE_OPEN_CREATE, is used to indicate that file should always
** be created, and that it is an error if it already exists.
** It is <i>not</i> used to indicate the file should be opened 
** for exclusive access.
**
** ^At least szOsFile bytes of memory are allocated by SQLite
** to hold the  [sqlite3_file] structure passed as the third
** argument to xOpen.  The xOpen method does not have to
** allocate the structure; it should just fill it in.  Note that
** the xOpen method must set the sqlite3_file.pMethods to either
** a valid [sqlite3_io_methods] object or to NULL.  xOpen must do
** this even if the open fails.  SQLite expects that the sqlite3_file.pMethods
** element will be valid after xOpen returns regardless of the success
** or failure of the xOpen call.







|







1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
** API.  The SQLITE_OPEN_EXCLUSIVE flag, when paired with the 
** SQLITE_OPEN_CREATE, is used to indicate that file should always
** be created, and that it is an error if it already exists.
** It is <i>not</i> used to indicate the file should be opened 
** for exclusive access.
**
** ^At least szOsFile bytes of memory are allocated by SQLite
** to hold the [sqlite3_file] structure passed as the third
** argument to xOpen.  The xOpen method does not have to
** allocate the structure; it should just fill it in.  Note that
** the xOpen method must set the sqlite3_file.pMethods to either
** a valid [sqlite3_io_methods] object or to NULL.  xOpen must do
** this even if the open fails.  SQLite expects that the sqlite3_file.pMethods
** element will be valid after xOpen returns regardless of the success
** or failure of the xOpen call.
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
** checks whether the file is readable.  The SQLITE_ACCESS_READ constant is
** currently unused, though it might be used in a future release of
** SQLite.
*/
#define SQLITE_ACCESS_EXISTS    0
#define SQLITE_ACCESS_READWRITE 1   /* Used by PRAGMA temp_store_directory */
#define SQLITE_ACCESS_READ      2   /* Unused */
#define SQLITE_ACCESS_SYMLINK   3   /* Test if file is symbolic link */

/*
** CAPI3REF: Flags for the xShmLock VFS method
**
** These integer constants define the various locking operations
** allowed by the xShmLock method of [sqlite3_io_methods].  The
** following are the only legal combinations of flags to the







<







1416
1417
1418
1419
1420
1421
1422

1423
1424
1425
1426
1427
1428
1429
** checks whether the file is readable.  The SQLITE_ACCESS_READ constant is
** currently unused, though it might be used in a future release of
** SQLite.
*/
#define SQLITE_ACCESS_EXISTS    0
#define SQLITE_ACCESS_READWRITE 1   /* Used by PRAGMA temp_store_directory */
#define SQLITE_ACCESS_READ      2   /* Unused */


/*
** CAPI3REF: Flags for the xShmLock VFS method
**
** These integer constants define the various locking operations
** allowed by the xShmLock method of [sqlite3_io_methods].  The
** following are the only legal combinations of flags to the
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
** allocators round up memory allocations at least to the next multiple
** of 8.  Some allocators round up to a larger multiple or to a power of 2.
** Every memory allocation request coming in through [sqlite3_malloc()]
** or [sqlite3_realloc()] first calls xRoundup.  If xRoundup returns 0, 
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator.  For example,
** it might allocate any require mutexes or initialize internal data
** structures.  The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
** by xInit.  The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe.  The







|







1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
** allocators round up memory allocations at least to the next multiple
** of 8.  Some allocators round up to a larger multiple or to a power of 2.
** Every memory allocation request coming in through [sqlite3_malloc()]
** or [sqlite3_realloc()] first calls xRoundup.  If xRoundup returns 0, 
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator.  For example,
** it might allocate any required mutexes or initialize internal data
** structures.  The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
** by xInit.  The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe.  The
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
** that SQLite can use for the database page cache with the default page
** cache implementation.  
** This configuration option is a no-op if an application-define page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned memory (pMem), the size of each page cache line (sz),
** and the number of cache lines (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 65536) plus some extra bytes for each
** page header.  ^The number of extra bytes needed by the page header







|







1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
** that SQLite can use for the database page cache with the default page
** cache implementation.  
** This configuration option is a no-op if an application-defined page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned memory (pMem), the size of each page cache line (sz),
** and the number of cache lines (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 65536) plus some extra bytes for each
** page header.  ^The number of extra bytes needed by the page header
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265





















2266
2267
2268
2269
2270
2271
2272
** additional information. This feature can also be turned on and off
** using the [PRAGMA legacy_alter_table] statement.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
** <dt>SQLITE_DBCONFIG_DQS_DML</td>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statement
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>





















**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag.  When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
** integer found at offset 44 into the database header) of 1.  This in turn







|













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







2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
** additional information. This feature can also be turned on and off
** using the [PRAGMA legacy_alter_table] statement.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
** <dt>SQLITE_DBCONFIG_DQS_DML</td>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas (the contents of the [sqlite_master] tables)
** are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
** takes additional defensive steps to protect the application from harm
** including:
** <ul>
** <li> Prohibit the use of SQL functions inside triggers, views,
** CHECK constraints, DEFAULT clauses, expression indexes, 
** partial indexes, or generated columns
** unless those functions are tagged with [SQLITE_INNOCUOUS].
** <li> Prohibit the use of virtual tables inside of triggers or views
** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS].
** </ul>
** This setting defaults to "on" for legacy compatibility, however
** all applications are advised to turn it off if possible. This setting
** can also be controlled using the [PRAGMA trusted_schema] statement.
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag.  When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
** integer found at offset 44 into the database header) of 1.  This in turn
2300
2301
2302
2303
2304
2305
2306

2307
2308
2309
2310
2311
2312
2313
2314
#define SQLITE_DBCONFIG_DEFENSIVE             1010 /* int int* */
#define SQLITE_DBCONFIG_WRITABLE_SCHEMA       1011 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE    1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML               1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL               1014 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_VIEW           1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    1016 /* int int* */

#define SQLITE_DBCONFIG_MAX                   1016 /* Largest DBCONFIG */

/*
** CAPI3REF: Enable Or Disable Extended Result Codes
** METHOD: sqlite3
**
** ^The sqlite3_extended_result_codes() routine enables or disables the
** [extended result codes] feature of SQLite. ^The extended result







>
|







2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
#define SQLITE_DBCONFIG_DEFENSIVE             1010 /* int int* */
#define SQLITE_DBCONFIG_WRITABLE_SCHEMA       1011 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE    1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML               1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL               1014 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_VIEW           1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT    1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA        1017 /* int int* */
#define SQLITE_DBCONFIG_MAX                   1017 /* Largest DBCONFIG */

/*
** CAPI3REF: Enable Or Disable Extended Result Codes
** METHOD: sqlite3
**
** ^The sqlite3_extended_result_codes() routine enables or disables the
** [extended result codes] feature of SQLite. ^The extended result
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE
** that is inside an explicit transaction, then the entire transaction
** will be rolled back automatically.
**
** ^The sqlite3_interrupt(D) call is in effect until all currently running
** SQL statements on [database connection] D complete.  ^Any new SQL statements
** that are started after the sqlite3_interrupt() call and before the 
** running statements reaches zero are interrupted as if they had been
** running prior to the sqlite3_interrupt() call.  ^New SQL statements
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
*/







|







2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE
** that is inside an explicit transaction, then the entire transaction
** will be rolled back automatically.
**
** ^The sqlite3_interrupt(D) call is in effect until all currently running
** SQL statements on [database connection] D complete.  ^Any new SQL statements
** that are started after the sqlite3_interrupt() call and before the 
** running statement count reaches zero are interrupted as if they had been
** running prior to the sqlite3_interrupt() call.  ^New SQL statements
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
*/
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
**        Name        | Age
**        -----------------------
**        Alice       | 43
**        Bob         | 28
**        Cindy       | 21
** </pre></blockquote>
**
** There are two column (M==2) and three rows (N==3).  Thus the
** result table has 8 entries.  Suppose the result table is stored
** in an array names azResult.  Then azResult holds this content:
**
** <blockquote><pre>
**        azResult&#91;0] = "Name";
**        azResult&#91;1] = "Age";
**        azResult&#91;2] = "Alice";
**        azResult&#91;3] = "43";
**        azResult&#91;4] = "Bob";







|

|







2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
**        Name        | Age
**        -----------------------
**        Alice       | 43
**        Bob         | 28
**        Cindy       | 21
** </pre></blockquote>
**
** There are two columns (M==2) and three rows (N==3).  Thus the
** result table has 8 entries.  Suppose the result table is stored
** in an array named azResult.  Then azResult holds this content:
**
** <blockquote><pre>
**        azResult&#91;0] = "Name";
**        azResult&#91;1] = "Age";
**        azResult&#91;2] = "Alice";
**        azResult&#91;3] = "43";
**        azResult&#91;4] = "Bob";
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);

/*
** CAPI3REF: Memory Allocation Subsystem
**
** The SQLite core uses these three routines for all of its own
** internal memory allocation needs. "Core" in the previous sentence
** does not include operating-system specific VFS implementation.  The
** Windows VFS uses native malloc() and free() for some operations.
**
** ^The sqlite3_malloc() routine returns a pointer to a block
** of memory at least N bytes in length, where N is the parameter.
** ^If sqlite3_malloc() is unable to obtain sufficient free
** memory, it returns a NULL pointer.  ^If the parameter N to
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns







|







2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);

/*
** CAPI3REF: Memory Allocation Subsystem
**
** The SQLite core uses these three routines for all of its own
** internal memory allocation needs. "Core" in the previous sentence
** does not include operating-system specific [VFS] implementation.  The
** Windows VFS uses native malloc() and free() for some operations.
**
** ^The sqlite3_malloc() routine returns a pointer to a block
** of memory at least N bytes in length, where N is the parameter.
** ^If sqlite3_malloc() is unable to obtain sufficient free
** memory, it returns a NULL pointer.  ^If the parameter N to
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
**
** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
** sqlite3_malloc64(), and sqlite3_realloc64()
** is always aligned to at least an 8 byte boundary, or to a
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
**
** In SQLite version 3.5.0 and 3.5.1, it was possible to define
** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
** implementation of these routines to be omitted.  That capability
** is no longer provided.  Only built-in memory allocators can be used.
**
** Prior to SQLite version 3.7.10, the Windows OS interface layer called
** the system malloc() and free() directly when converting
** filenames between the UTF-8 encoding used by SQLite
** and whatever filename encoding is used by the particular Windows
** installation.  Memory allocation errors were detected, but
** they were reported back as [SQLITE_CANTOPEN] or
** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
**
** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
** must be either NULL or else pointers obtained from a prior
** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
** not yet been released.
**
** The application must not read or write any part of
** a block of memory after it has been released using







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







2863
2864
2865
2866
2867
2868
2869













2870
2871
2872
2873
2874
2875
2876
**
** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
** sqlite3_malloc64(), and sqlite3_realloc64()
** is always aligned to at least an 8 byte boundary, or to a
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
**













** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
** must be either NULL or else pointers obtained from a prior
** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
** not yet been released.
**
** The application must not read or write any part of
** a block of memory after it has been released using
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905

/*
** CAPI3REF: Pseudo-Random Number Generator
**
** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
** select random [ROWID | ROWIDs] when inserting new records into a table that
** already uses the largest possible [ROWID].  The PRNG is also used for
** the build-in random() and randomblob() SQL functions.  This interface allows
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
** call had N less than one or a NULL pointer for P, then the PRNG is







|







2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925

/*
** CAPI3REF: Pseudo-Random Number Generator
**
** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
** select random [ROWID | ROWIDs] when inserting new records into a table that
** already uses the largest possible [ROWID].  The PRNG is also used for
** the built-in random() and randomblob() SQL functions.  This interface allows
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
** call had N less than one or a NULL pointer for P, then the PRNG is
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292








































3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
** passing it to [sqlite3_close()] when it is no longer required.
**
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
** over the new database connection.  ^(The flags parameter to
** sqlite3_open_v2() can take one of
** the following three values, optionally combined with the 
** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
** <dd>The database is opened in read-only mode.  If the database does not
** already exist, an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
** <dd>The database is opened for reading and writing if possible, or reading
** only if the file is write protected by the operating system.  In either
** case the database must already exist, otherwise an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
** <dd>The database is opened for reading and writing, and is created if
** it does not already exist. This is the behavior that is always used for
** sqlite3_open() and sqlite3_open16().</dd>)^
** </dl>
**








































** If the 3rd parameter to sqlite3_open_v2() is not one of the
** combinations shown above optionally combined with other
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
** then the behavior is undefined.
**
** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
** opens in the multi-thread [threading mode] as long as the single-thread
** mode has not been set at compile-time or start-time.  ^If the
** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens
** in the serialized [threading mode] unless single-thread was
** previously selected at compile-time or start-time.
** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be
** eligible to use [shared cache mode], regardless of whether or not shared
** cache is enabled using [sqlite3_enable_shared_cache()].  ^The
** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
** participate in [shared cache mode] even if it is enabled.
**
** ^The fourth parameter to sqlite3_open_v2() is the name of the
** [sqlite3_vfs] object that defines the operating system interface that
** the new database connection should use.  ^If the fourth parameter is
** a NULL pointer then the default [sqlite3_vfs] object is used.
**
** ^If the filename is ":memory:", then a private, temporary in-memory database
** is created for the connection.  ^This in-memory database will vanish when







|
|
<
<

















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

|



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







3285
3286
3287
3288
3289
3290
3291
3292
3293


3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355












3356
3357
3358
3359
3360
3361
3362
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
** passing it to [sqlite3_close()] when it is no longer required.
**
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
** over the new database connection.  ^(The flags parameter to
** sqlite3_open_v2() must include, at a minimum, one of the following
** three flag combinations:)^


**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
** <dd>The database is opened in read-only mode.  If the database does not
** already exist, an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
** <dd>The database is opened for reading and writing if possible, or reading
** only if the file is write protected by the operating system.  In either
** case the database must already exist, otherwise an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
** <dd>The database is opened for reading and writing, and is created if
** it does not already exist. This is the behavior that is always used for
** sqlite3_open() and sqlite3_open16().</dd>)^
** </dl>
**
** In addition to the required flags, the following optional flags are
** also supported:
**
** <dl>
** ^(<dt>[SQLITE_OPEN_URI]</dt>
** <dd>The filename can be interpreted as a URI if this flag is set.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_MEMORY]</dt>
** <dd>The database will be opened as an in-memory database.  The database
** is named by the "filename" argument for the purposes of cache-sharing,
** if shared cache mode is enabled, but the "filename" is otherwise ignored.
** </dd>)^
**
** ^(<dt>[SQLITE_OPEN_NOMUTEX]</dt>
** <dd>The new database connection will use the "multi-thread"
** [threading mode].)^  This means that separate threads are allowed
** to use SQLite at the same time, as long as each thread is using
** a different [database connection].
**
** ^(<dt>[SQLITE_OPEN_FULLMUTEX]</dt>
** <dd>The new database connection will use the "serialized"
** [threading mode].)^  This means the multiple threads can safely
** attempt to use the same database connection at the same time.
** (Mutexes will block any actual concurrency, but in this mode
** there is no harm in trying.)
**
** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt>
** <dd>The database is opened [shared cache] enabled, overriding
** the default shared cache setting provided by
** [sqlite3_enable_shared_cache()].)^
**
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
** <dd>The database is opened [shared cache] disabled, overriding
** the default shared cache setting provided by
** [sqlite3_enable_shared_cache()].)^
**
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
** <dd>The database filename is not allowed to be a symbolic link</dd>
** </dl>)^
**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
** required combinations shown above optionally combined with other
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
** then the behavior is undefined.
**












** ^The fourth parameter to sqlite3_open_v2() is the name of the
** [sqlite3_vfs] object that defines the operating system interface that
** the new database connection should use.  ^If the fourth parameter is
** a NULL pointer then the default [sqlite3_vfs] object is used.
**
** ^If the filename is ":memory:", then a private, temporary in-memory database
** is created for the connection.  ^This in-memory database will vanish when
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517







3518
3519
3520
3521
3522
3523








3524
3525
3526
3527
3528
3529

3530




















































































3531
3532
3533
3534
3535
3536
3537
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);

/*
** CAPI3REF: Obtain Values For URI Parameters
**
** These are utility routines, useful to VFS implementations, that check
** to see if a database file was a URI that contained a specific query 
** parameter, and if so obtains the value of that query parameter.
**
** If F is the database filename pointer passed into the xOpen() method of 
** a VFS implementation when the flags parameter to xOpen() has one or 
** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and
** P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
** parameter if it exists or a NULL pointer if P does not appear as a 
** query parameter on F.  If P is a query parameter of F
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
** a pointer to an empty string.
**
** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean
** parameter and returns true (1) or false (0) according to the value
** of P.  The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
** value of query parameter P is one of "yes", "true", or "on" in any
** case or if the value begins with a non-zero number.  The 
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
** query parameter P is one of "no", "false", or "off" in any case or
** if the value begins with a numeric zero.  If P is not a query
** parameter on F or if the value of P is does not match any of the
** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
**
** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
** 64-bit signed integer and returns that integer, or D if P does not
** exist.  If the value of P is something other than an integer, then
** zero is returned.







** 
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
** sqlite3_uri_boolean(F,P,B) returns B.  If F is not a NULL pointer and
** is not a database file pathname pointer that SQLite passed into the xOpen
** VFS method, then the behavior of this routine is undefined and probably
** undesirable.








**
** See the [URI filename] documentation for additional information.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);























































































/*
** CAPI3REF: Error Codes And Messages
** METHOD: sqlite3
**
** ^If the most recent sqlite3_* API call associated with 
** [database connection] D failed, then the sqlite3_errcode(D) interface







|
|



|
<
|


|











|






>
>
>
>
>
>
>



|
|
|
>
>
>
>
>
>
>
>






>

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







3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540

3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);

/*
** CAPI3REF: Obtain Values For URI Parameters
**
** These are utility routines, useful to [VFS|custom VFS implementations],
** that check if a database file was a URI that contained a specific query 
** parameter, and if so obtains the value of that query parameter.
**
** If F is the database filename pointer passed into the xOpen() method of 
** a VFS implementation or it is the return value of [sqlite3_db_filename()]

** and if P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
** parameter if it exists or a NULL pointer if P does not appear as a 
** query parameter on F.  If P is a query parameter of F and it
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
** a pointer to an empty string.
**
** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean
** parameter and returns true (1) or false (0) according to the value
** of P.  The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
** value of query parameter P is one of "yes", "true", or "on" in any
** case or if the value begins with a non-zero number.  The 
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
** query parameter P is one of "no", "false", or "off" in any case or
** if the value begins with a numeric zero.  If P is not a query
** parameter on F or if the value of P does not match any of the
** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
**
** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
** 64-bit signed integer and returns that integer, or D if P does not
** exist.  If the value of P is something other than an integer, then
** zero is returned.
**
** The sqlite3_uri_key(F,N) returns a pointer to the name (not
** the value) of the N-th query parameter for filename F, or a NULL
** pointer if N is less than zero or greater than the number of query
** parameters minus 1.  The N value is zero-based so N should be 0 to obtain
** the name of the first query parameter, 1 for the second parameter, and
** so forth.
** 
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
** sqlite3_uri_boolean(F,P,B) returns B.  If F is not a NULL pointer and
** is not a database file pathname pointer that the SQLite core passed
** into the xOpen VFS method, then the behavior of this routine is undefined
** and probably undesirable.
**
** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F
** parameter can also be the name of a rollback journal file or WAL file
** in addition to the main database file.  Prior to version 3.31.0, these
** routines would only work if F was the name of the main database file.
** When the F parameter is the name of the rollback journal or WAL file,
** it has access to all the same query parameters as were found on the
** main database file.
**
** See the [URI filename] documentation for additional information.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);

/*
** CAPI3REF:  Translate filenames
**
** These routines are available to [VFS|custom VFS implementations] for
** translating filenames between the main database file, the journal file,
** and the WAL file.
**
** If F is the name of an sqlite database file, journal file, or WAL file
** passed by the SQLite core into the VFS, then sqlite3_filename_database(F)
** returns the name of the corresponding database file.
**
** If F is the name of an sqlite database file, journal file, or WAL file
** passed by the SQLite core into the VFS, or if F is a database filename
** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F)
** returns the name of the corresponding rollback journal file.
**
** If F is the name of an sqlite database file, journal file, or WAL file
** that was passed by the SQLite core into the VFS, or if F is a database
** filename obtained from [sqlite3_db_filename()], then
** sqlite3_filename_wal(F) returns the name of the corresponding
** WAL file.
**
** In all of the above, if F is not the name of a database, journal or WAL
** filename passed into the VFS from the SQLite core and F is not the
** return value from [sqlite3_db_filename()], then the result is
** undefined and is likely a memory access violation.
*/
SQLITE_API const char *sqlite3_filename_database(const char*);
SQLITE_API const char *sqlite3_filename_journal(const char*);
SQLITE_API const char *sqlite3_filename_wal(const char*);

/*
** CAPI3REF: Create and Destroy VFS Filenames
**
** These interfces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
** database filename D with corresponding journal file J and WAL file W and
** with N URI parameters key/values pairs in the array P.  The result from
** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
** is safe to pass to routines like:
** <ul>
** <li> [sqlite3_uri_parameter()],
** <li> [sqlite3_uri_boolean()],
** <li> [sqlite3_uri_int64()],
** <li> [sqlite3_uri_key()], 
** <li> [sqlite3_filename_database()],
** <li> [sqlite3_filename_journal()], or
** <li> [sqlite3_filename_wal()].
** </ul>
** If a memory allocation error occurs, sqlite3_create_filename() might
** return a NULL pointer.  The memory obtained from sqlite3_create_filename(X)
** must be released by a corresponding call to sqlite3_free_filename(Y).
**
** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array
** of 2*N pointers to strings.  Each pair of pointers in this array corresponds
** to a key and value for a query parameter.  The P parameter may be a NULL
** pointer if N is zero.  None of the 2*N pointers in the P array may be
** NULL pointers and key pointers should not be empty strings.
** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may
** be NULL pointers, though they can be empty strings.
**
** The sqlite3_free_filename(Y) routine releases a memory allocation
** previously obtained from sqlite3_create_filename().  Invoking
** sqlite3_free_filename(Y) is a NULL pointer is a harmless no-op.
**
** If the Y parameter to sqlite3_free_filename(Y) is anything other
** than a NULL pointer or a pointer previously acquired from
** sqlite3_create_filename(), then bad things such as heap
** corruption or segfaults may occur. The value Y should be 
** used again after sqlite3_free_filename(Y) has been called.  This means
** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
** then the corresponding [sqlite3_module.xClose() method should also be
** invoked prior to calling sqlite3_free_filename(Y).
*/
SQLITE_API char *sqlite3_create_filename(
  const char *zDatabase,
  const char *zJournal,
  const char *zWal,
  int nParam,
  const char **azParam
);
SQLITE_API void sqlite3_free_filename(char*);

/*
** CAPI3REF: Error Codes And Messages
** METHOD: sqlite3
**
** ^If the most recent sqlite3_* API call associated with 
** [database connection] D failed, then the sqlite3_errcode(D) interface
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code
** and the application would have to make a second call to [sqlite3_reset()]
** in order to find the underlying cause of the problem. With the "v2" prepare
** interfaces, the underlying reason for the error is returned immediately.
** </li>
**
** <li>
** ^If the specific value bound to [parameter | host parameter] in the 
** WHERE clause might influence the choice of query plan for a statement,
** then the statement will be automatically recompiled, as if there had been 
** a schema change, on the first  [sqlite3_step()] call following any change
** to the [sqlite3_bind_text | bindings] of that [parameter]. 
** ^The specific value of WHERE-clause [parameter] might influence the 
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
** </li>
** </ol>
**
** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having







|


|

|







3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code
** and the application would have to make a second call to [sqlite3_reset()]
** in order to find the underlying cause of the problem. With the "v2" prepare
** interfaces, the underlying reason for the error is returned immediately.
** </li>
**
** <li>
** ^If the specific value bound to a [parameter | host parameter] in the 
** WHERE clause might influence the choice of query plan for a statement,
** then the statement will be automatically recompiled, as if there had been 
** a schema change, on the first [sqlite3_step()] call following any change
** to the [sqlite3_bind_text | bindings] of that [parameter]. 
** ^The specific value of a WHERE-clause [parameter] might influence the 
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
** </li>
** </ol>
**
** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118


















4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
** ^The leftmost SQL parameter has an index of 1.  ^When the same named
** SQL parameter is used more than once, second and subsequent
** occurrences have the same index as the first occurrence.
** ^The index for named parameters can be looked up using the
** [sqlite3_bind_parameter_index()] API if desired.  ^The index
** for "?NNN" parameters is the value of NNN.
** ^The NNN value must be between 1 and the [sqlite3_limit()]
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
**
** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().


















**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter.  To be clear: the value is the
** number of <u>bytes</u> in the value, not the number of characters.)^
** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** is negative, then the length of the string is
** the number of bytes up to the first zero terminator.
** If the fourth parameter to sqlite3_bind_blob() is negative, then
** the behavior is undefined.
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated.  If any NUL characters occur at byte offsets less than 
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs.  The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it.  ^The destructor is called







|





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













|







4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
** ^The leftmost SQL parameter has an index of 1.  ^When the same named
** SQL parameter is used more than once, second and subsequent
** occurrences have the same index as the first occurrence.
** ^The index for named parameters can be looked up using the
** [sqlite3_bind_parameter_index()] API if desired.  ^The index
** for "?NNN" parameters is the value of NNN.
** ^The NNN value must be between 1 and the [sqlite3_limit()]
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766).
**
** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().
** ^If the third parameter to sqlite3_bind_text() is not NULL, then
** it should be a pointer to well-formed UTF8 text.
** ^If the third parameter to sqlite3_bind_text16() is not NULL, then
** it should be a pointer to well-formed UTF16 text.
** ^If the third parameter to sqlite3_bind_text64() is not NULL, then
** it should be a pointer to a well-formed unicode string that is
** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16
** otherwise.
**
** [[byte-order determination rules]] ^The byte-order of
** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
** found in first character, which is removed, or in the absence of a BOM
** the byte order is the native byte order of the host
** machine for sqlite3_bind_text16() or the byte order specified in
** the 6th parameter for sqlite3_bind_text64().)^ 
** ^If UTF16 input text contains invalid unicode
** characters, then SQLite might change those invalid characters
** into the unicode replacement character: U+FFFD.
**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter.  To be clear: the value is the
** number of <u>bytes</u> in the value, not the number of characters.)^
** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** is negative, then the length of the string is
** the number of bytes up to the first zero terminator.
** If the fourth parameter to sqlite3_bind_blob() is negative, then
** the behavior is undefined.
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated.  If any NUL characters occurs at byte offsets less than 
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs.  The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it.  ^The destructor is called
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
** ^The first argument to these interfaces is a [prepared statement].
** ^These functions return information about the Nth result column returned by
** the statement, where N is the second function argument.
** ^The left-most column is column 0 for these routines.
**
** ^If the Nth column returned by the statement is an expression or
** subquery and is not a column value, then all of these functions return
** NULL.  ^These routine might also return NULL if a memory allocation error
** occurs.  ^Otherwise, they return the name of the attached database, table,
** or column that query result column was extracted from.
**
** ^As with all other SQLite APIs, those whose names end with "16" return
** UTF-16 encoded strings and the other functions return UTF-8.
**
** ^These APIs are only available if the library was compiled with the
** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
**
** If two or more threads call one or more of these routines against the same
** prepared statement and column at the same time then the results are
** undefined.
**
** If two or more threads call one or more
** [sqlite3_column_database_name | column metadata interfaces]
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);







|









<
<
<
<







4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534




4535
4536
4537
4538
4539
4540
4541
** ^The first argument to these interfaces is a [prepared statement].
** ^These functions return information about the Nth result column returned by
** the statement, where N is the second function argument.
** ^The left-most column is column 0 for these routines.
**
** ^If the Nth column returned by the statement is an expression or
** subquery and is not a column value, then all of these functions return
** NULL.  ^These routines might also return NULL if a memory allocation error
** occurs.  ^Otherwise, they return the name of the attached database, table,
** or column that query result column was extracted from.
**
** ^As with all other SQLite APIs, those whose names end with "16" return
** UTF-16 encoded strings and the other functions return UTF-8.
**
** ^These APIs are only available if the library was compiled with the
** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
**




** If two or more threads call one or more
** [sqlite3_column_database_name | column metadata interfaces]
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
/*
** CAPI3REF: Number of columns in a result set
** METHOD: sqlite3_stmt
**
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
** ^If prepared statement P does not have results ready to return
** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
** interfaces) then sqlite3_data_count(P) returns 0.
** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
** [sqlite3_step](P) returned [SQLITE_DONE].  ^The sqlite3_data_count(P)
** will return non-zero if previous call to [sqlite3_step](P) returned
** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum]
** where it always returns zero since each step of that multi-step







|







4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
/*
** CAPI3REF: Number of columns in a result set
** METHOD: sqlite3_stmt
**
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
** ^If prepared statement P does not have results ready to return
** (via calls to the [sqlite3_column_int | sqlite3_column()] family of
** interfaces) then sqlite3_data_count(P) returns 0.
** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
** [sqlite3_step](P) returned [SQLITE_DONE].  ^The sqlite3_data_count(P)
** will return non-zero if previous call to [sqlite3_step](P) returned
** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum]
** where it always returns zero since each step of that multi-step
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);

/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
** KEYWORDS: {application-defined SQL function}
** KEYWORDS: {application-defined SQL functions}
** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
** of existing SQL functions or aggregates. The only differences between
** the three "sqlite3_create_function*" routines are the text encoding 
** expected for the second parameter (the name of the function being 







<
<







4988
4989
4990
4991
4992
4993
4994


4995
4996
4997
4998
4999
5000
5001
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);

/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}


** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
** of existing SQL functions or aggregates. The only differences between
** the three "sqlite3_create_function*" routines are the text encoding 
** expected for the second parameter (the name of the function being 
4886
4887
4888
4889
4890
4891
4892




4893
4894







4895
4896
4897
4898
4899
4900
4901
4902
** deterministic.  The built-in [random()] SQL function is an example of a
** function that is not deterministic.  The SQLite query planner is able to
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
** flag, which if present prevents the function from being invoked from




** within VIEWs or TRIGGERs.  For security reasons, the [SQLITE_DIRECTONLY]
** flag is recommended for any application-defined SQL function that has







** side-effects.
**
** ^(The fifth parameter is an arbitrary pointer.  The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
**
** ^The sixth, seventh and eighth parameters passed to the three
** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are
** pointers to C-language functions that implement the SQL function or







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







5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
** deterministic.  The built-in [random()] SQL function is an example of a
** function that is not deterministic.  The SQLite query planner is able to
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
** flag, which if present prevents the function from being invoked from
** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
** index expressions, or the WHERE clause of partial indexes.
**
** <span style="background-color:#ffff90;">
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
** all application-defined SQL functions that do not need to be
** used inside of triggers, view, CHECK constraints, or other elements of
** the database schema.  This flags is especially recommended for SQL 
** functions that have side effects or reveal internal application state.
** Without this flag, an attacker might be able to modify the schema of
** a database file to include invocations of the function with parameters
** chosen by the attacker, which the application will then execute when
** the database file is opened and read.
** </span>
**
** ^(The fifth parameter is an arbitrary pointer.  The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
**
** ^The sixth, seventh and eighth parameters passed to the three
** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are
** pointers to C-language functions that implement the SQL function or
5007
5008
5009
5010
5011
5012
5013


5014
5015
5016






5017

5018
5019


5020
5021

















5022




5023


5024
5025

5026
5027
5028
5029
5030
5031
5032


5033
5034
5035
5036

5037
5038
5039
5040
5041
5042
5043
** CAPI3REF: Function Flags
**
** These constants may be ORed together with the 
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
**


** The SQLITE_DETERMINISTIC flag means that the new function will always
** maps the same inputs into the same output.  The abs() function is
** deterministic, for example, but randomblob() is not.






**

** The SQLITE_DIRECTONLY flag means that the function may only be invoked
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs.  This is


** a security feature which is recommended for all 
** [application-defined SQL functions] that have side-effects.  This flag 

















** prevents an attacker from adding triggers and views to a schema then 




** tricking a high-privilege application into causing unintended side-effects


** while performing ordinary queries.
**

** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
** Specifying this flag makes no difference for scalar or aggregate user
** functions. However, if it is not specified for a user-defined window
** function, then any sub-types belonging to arguments passed to the window
** function may be discarded before the window function is called (i.e.
** sqlite3_value_subtype() will always return 0).


*/
#define SQLITE_DETERMINISTIC    0x000000800
#define SQLITE_DIRECTONLY       0x000080000
#define SQLITE_SUBTYPE          0x000100000


/*
** CAPI3REF: Deprecated Functions
** DEPRECATED
**
** These functions are [deprecated].  In order to maintain
** backwards compatibility with older code, these functions continue 







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

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

>







>
>




>







5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
** CAPI3REF: Function Flags
**
** These constants may be ORed together with the 
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
**
** <dl>
** [[SQLITE_DETERMINISTIC]] <dt>SQLITE_DETERMINISTIC</dt><dd>
** The SQLITE_DETERMINISTIC flag means that the new function always gives
** the same output when the input parameters are the same.
** The [abs|abs() function] is deterministic, for example, but
** [randomblob|randomblob()] is not.  Functions must
** be deterministic in order to be used in certain contexts such as
** with the WHERE clause of [partial indexes] or in [generated columns].
** SQLite might also optimize deterministic functions by factoring them
** out of inner loops.
** </dd>
** 
** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd>
** The SQLITE_DIRECTONLY flag means that the function may only be invoked
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in 
** schema structures such as [CHECK constraints], [DEFAULT clauses],
** [expression indexes], [partial indexes], or [generated columns].
** The SQLITE_DIRECTONLY flags is a security feature which is recommended
** for all [application-defined SQL functions], and especially for functions
** that have side-effects or that could potentially leak sensitive
** information.
** </dd>
**
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
** The SQLITE_INNOCUOUS flag means that the function is unlikely
** to cause problems even if misused.  An innocuous function should have
** no side effects and should not depend on any values other than its
** input parameters. The [abs|abs() function] is an example of an
** innocuous function.
** The [load_extension() SQL function] is not innocuous because of its
** side effects.
** <p> SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not
** exactly the same.  The [random|random() function] is an example of a
** function that is innocuous but not deterministic.
** <p>Some heightened security settings
** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF])
** disable the use of SQL functions inside views and triggers and in
** schema structures such as [CHECK constraints], [DEFAULT clauses],
** [expression indexes], [partial indexes], and [generated columns] unless
** the function is tagged with SQLITE_INNOCUOUS.  Most built-in functions
** are innocuous.  Developers are advised to avoid using the
** SQLITE_INNOCUOUS flag for application-defined functions unless the
** function has been carefully audited and found to be free of potentially
** security-adverse side-effects and information-leaks.
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
** Specifying this flag makes no difference for scalar or aggregate user
** functions. However, if it is not specified for a user-defined window
** function, then any sub-types belonging to arguments passed to the window
** function may be discarded before the window function is called (i.e.
** sqlite3_value_subtype() will always return 0).
** </dd>
** </dl>
*/
#define SQLITE_DETERMINISTIC    0x000000800
#define SQLITE_DIRECTONLY       0x000080000
#define SQLITE_SUBTYPE          0x000100000
#define SQLITE_INNOCUOUS        0x000200000

/*
** CAPI3REF: Deprecated Functions
** DEPRECATED
**
** These functions are [deprecated].  In order to maintain
** backwards compatibility with older code, these functions continue 
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
** <td>&rarr;&nbsp;&nbsp;<td>True if value originated from a [bound parameter]
** </table></blockquote>
**
** <b>Details:</b>
**
** These routines extract type, size, and content information from
** [protected sqlite3_value] objects.  Protected sqlite3_value objects
** are used to pass parameter information into implementation of
** [application-defined SQL functions] and [virtual tables].
**
** These routines work only with [protected sqlite3_value] objects.
** Any attempt to use these routines on an [unprotected sqlite3_value]
** is not threadsafe.
**
** ^These routines work just like the corresponding [column access functions]
** except that these routines take a single [protected sqlite3_value] object







|
|







5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
** <td>&rarr;&nbsp;&nbsp;<td>True if value originated from a [bound parameter]
** </table></blockquote>
**
** <b>Details:</b>
**
** These routines extract type, size, and content information from
** [protected sqlite3_value] objects.  Protected sqlite3_value objects
** are used to pass parameter information into the functions that
** implement [application-defined SQL functions] and [virtual tables].
**
** These routines work only with [protected sqlite3_value] objects.
** Any attempt to use these routines on an [unprotected sqlite3_value]
** is not threadsafe.
**
** ^These routines work just like the corresponding [column access functions]
** except that these routines take a single [protected sqlite3_value] object
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
** than within an [xUpdate] method call for an UPDATE statement, then
** the return value is arbitrary and meaningless.
**
** ^The sqlite3_value_frombind(X) interface returns non-zero if the
** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()]
** interfaces.  ^If X comes from an SQL literal value, or a table column,
** and expression, then sqlite3_value_frombind(X) returns zero.
**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
** [sqlite3_value_text16()] can be invalidated by a subsequent call to
** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
** or [sqlite3_value_text16()].
**







|







5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
** than within an [xUpdate] method call for an UPDATE statement, then
** the return value is arbitrary and meaningless.
**
** ^The sqlite3_value_frombind(X) interface returns non-zero if the
** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()]
** interfaces.  ^If X comes from an SQL literal value, or a table column,
** or an expression, then sqlite3_value_frombind(X) returns zero.
**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
** [sqlite3_value_text16()] can be invalidated by a subsequent call to
** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
** or [sqlite3_value_text16()].
**
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
** CAPI3REF: Obtain Aggregate Function Context
** METHOD: sqlite3_context
**
** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
**
** ^The first time the sqlite3_aggregate_context(C,N) routine is called 
** for a particular aggregate function, SQLite
** allocates N of memory, zeroes out that memory, and returns a pointer
** to the new memory. ^On second and subsequent calls to
** sqlite3_aggregate_context() for the same aggregate function instance,
** the same buffer is returned.  Sqlite3_aggregate_context() is normally
** called once for each invocation of the xStep callback and then one
** last time when the xFinal callback is invoked.  ^(When no rows match
** an aggregate query, the xStep() callback of the aggregate function
** implementation is never called and xFinal() is called exactly once.
** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^
**
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer 
** when first called if N is less than or equal to zero or if a memory
** allocate error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call.  Changing the
** value of N in subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
** allocation.)^  Within the xFinal callback, it is customary to set
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no 
** pointless memory allocations occur.
**
** ^SQLite automatically frees the memory allocated by 
** sqlite3_aggregate_context() when the aggregate query concludes.







|
|
















|







5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
** CAPI3REF: Obtain Aggregate Function Context
** METHOD: sqlite3_context
**
** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
**
** ^The first time the sqlite3_aggregate_context(C,N) routine is called 
** for a particular aggregate function, SQLite allocates
** N bytes of memory, zeroes out that memory, and returns a pointer
** to the new memory. ^On second and subsequent calls to
** sqlite3_aggregate_context() for the same aggregate function instance,
** the same buffer is returned.  Sqlite3_aggregate_context() is normally
** called once for each invocation of the xStep callback and then one
** last time when the xFinal callback is invoked.  ^(When no rows match
** an aggregate query, the xStep() callback of the aggregate function
** implementation is never called and xFinal() is called exactly once.
** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^
**
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer 
** when first called if N is less than or equal to zero or if a memory
** allocate error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call.  Changing the
** value of N in any subsequents call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
** allocation.)^  Within the xFinal callback, it is customary to set
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no 
** pointless memory allocations occur.
**
** ^SQLite automatically frees the memory allocated by 
** sqlite3_aggregate_context() when the aggregate query concludes.
5407
5408
5409
5410
5411
5412
5413
5414

5415
5416
5417
5418
5419
5420
5421
5422
**
** ^The sqlite3_result_error() and sqlite3_result_error16() functions
** cause the implemented SQL function to throw an exception.
** ^SQLite uses the string pointed to by the
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
** as the text of an error message.  ^SQLite interprets the error
** message string from sqlite3_result_error() as UTF-8. ^SQLite
** interprets the string from sqlite3_result_error16() as UTF-16 in native

** byte order.  ^If the third parameter to sqlite3_result_error()
** or sqlite3_result_error16() is negative then SQLite takes as the error
** message all text up through the first zero character.
** ^If the third parameter to sqlite3_result_error() or
** sqlite3_result_error16() is non-negative then SQLite takes that many
** bytes (not characters) from the 2nd parameter as the error message.
** ^The sqlite3_result_error() and sqlite3_result_error16()
** routines make a private copy of the error message text before







|
>
|







5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
**
** ^The sqlite3_result_error() and sqlite3_result_error16() functions
** cause the implemented SQL function to throw an exception.
** ^SQLite uses the string pointed to by the
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
** as the text of an error message.  ^SQLite interprets the error
** message string from sqlite3_result_error() as UTF-8. ^SQLite
** interprets the string from sqlite3_result_error16() as UTF-16 using
** the same [byte-order determination rules] as [sqlite3_bind_text16()].
** ^If the third parameter to sqlite3_result_error()
** or sqlite3_result_error16() is negative then SQLite takes as the error
** message all text up through the first zero character.
** ^If the third parameter to sqlite3_result_error() or
** sqlite3_result_error16() is non-negative then SQLite takes that many
** bytes (not characters) from the 2nd parameter as the error message.
** ^The sqlite3_result_error() and sqlite3_result_error16()
** routines make a private copy of the error message text before
5475
5476
5477
5478
5479
5480
5481



















5482
5483
5484
5485
5486
5487
5488
** assumes that the text or BLOB result is in constant space and does not
** copy the content of the parameter nor call a destructor on the content
** when it has finished using that result.
** ^If the 4th parameter to the sqlite3_result_text* interfaces
** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
** then SQLite makes a copy of the result into space obtained
** from [sqlite3_malloc()] before it returns.



















**
** ^The sqlite3_result_value() interface sets the result of
** the application-defined function to be a copy of the
** [unprotected sqlite3_value] object specified by the 2nd parameter.  ^The
** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
** so that the [sqlite3_value] specified in the parameter may change or
** be deallocated after sqlite3_result_value() returns without harm.







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







5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
** assumes that the text or BLOB result is in constant space and does not
** copy the content of the parameter nor call a destructor on the content
** when it has finished using that result.
** ^If the 4th parameter to the sqlite3_result_text* interfaces
** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
** then SQLite makes a copy of the result into space obtained
** from [sqlite3_malloc()] before it returns.
**
** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and
** sqlite3_result_text16be() routines, and for sqlite3_result_text64()
** when the encoding is not UTF8, if the input UTF16 begins with a
** byte-order mark (BOM, U+FEFF) then the BOM is removed from the
** string and the rest of the string is interpreted according to the
** byte-order specified by the BOM.  ^The byte-order specified by
** the BOM at the beginning of the text overrides the byte-order
** specified by the interface procedure.  ^So, for example, if
** sqlite3_result_text16le() is invoked with text that begins
** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the
** first two bytes of input are skipped and the remaining input
** is interpreted as UTF16BE text.
**
** ^For UTF16 input text to the sqlite3_result_text16(),
** sqlite3_result_text16be(), sqlite3_result_text16le(), and
** sqlite3_result_text64() routines, if the text contains invalid
** UTF16 characters, the invalid characters might be converted
** into the unicode replacement character, U+FFFD.
**
** ^The sqlite3_result_value() interface sets the result of
** the application-defined function to be a copy of the
** [unprotected sqlite3_value] object specified by the 2nd parameter.  ^The
** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
** so that the [sqlite3_value] specified in the parameter may change or
** be deallocated after sqlite3_result_value() returns without harm.
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587

5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
** <li> [SQLITE_UTF8],
** <li> [SQLITE_UTF16LE],
** <li> [SQLITE_UTF16BE],
** <li> [SQLITE_UTF16], or
** <li> [SQLITE_UTF16_ALIGNED].
** </ul>)^
** ^The eTextRep argument determines the encoding of strings passed
** to the collating function callback, xCallback.
** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
** force strings to be UTF16 with native byte order.
** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
** on an even byte address.
**
** ^The fourth argument, pArg, is an application data pointer that is passed
** through as the first argument to the collating function callback.
**
** ^The fifth argument, xCallback, is a pointer to the collating function.
** ^Multiple collating functions can be registered using the same name but
** with different eTextRep parameters and SQLite will use whichever
** function requires the least amount of data transformation.
** ^If the xCallback argument is NULL then the collating function is
** deleted.  ^When all collating functions having the same name are deleted,
** that collation is no longer usable.
**
** ^The collating function callback is invoked with a copy of the pArg 
** application data pointer and with two strings in the encoding specified
** by the eTextRep argument.  The collating function must return an

** integer that is negative, zero, or positive
** if the first string is less than, equal to, or greater than the second,
** respectively.  A collating function must always return the same answer
** given the same inputs.  If two or more collating functions are registered
** to the same collation name (using different eTextRep values) then all
** must give an equivalent answer when invoked with equivalent strings.
** The collating function must obey the following properties for all
** strings A, B, and C:
**
** <ol>
** <li> If A==B then B==A.
** <li> If A==B and B==C then A==C.
** <li> If A&lt;B THEN B&gt;A.
** <li> If A&lt;B and B&lt;C then A&lt;C.
** </ol>
**
** If a collating function fails any of the above constraints and that
** collating function is  registered and used, then the behavior of SQLite
** is undefined.
**
** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
** with the addition that the xDestroy callback is invoked on pArg when
** the collating function is deleted.
** ^Collating functions are deleted when they are overridden by later
** calls to the collation creation functions or when the







|








|



|





|
>
|
















|







5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
** <li> [SQLITE_UTF8],
** <li> [SQLITE_UTF16LE],
** <li> [SQLITE_UTF16BE],
** <li> [SQLITE_UTF16], or
** <li> [SQLITE_UTF16_ALIGNED].
** </ul>)^
** ^The eTextRep argument determines the encoding of strings passed
** to the collating function callback, xCompare.
** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
** force strings to be UTF16 with native byte order.
** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
** on an even byte address.
**
** ^The fourth argument, pArg, is an application data pointer that is passed
** through as the first argument to the collating function callback.
**
** ^The fifth argument, xCompare, is a pointer to the collating function.
** ^Multiple collating functions can be registered using the same name but
** with different eTextRep parameters and SQLite will use whichever
** function requires the least amount of data transformation.
** ^If the xCompare argument is NULL then the collating function is
** deleted.  ^When all collating functions having the same name are deleted,
** that collation is no longer usable.
**
** ^The collating function callback is invoked with a copy of the pArg 
** application data pointer and with two strings in the encoding specified
** by the eTextRep argument.  The two integer parameters to the collating
** function callback are the length of the two strings, in bytes. The collating
** function must return an integer that is negative, zero, or positive
** if the first string is less than, equal to, or greater than the second,
** respectively.  A collating function must always return the same answer
** given the same inputs.  If two or more collating functions are registered
** to the same collation name (using different eTextRep values) then all
** must give an equivalent answer when invoked with equivalent strings.
** The collating function must obey the following properties for all
** strings A, B, and C:
**
** <ol>
** <li> If A==B then B==A.
** <li> If A==B and B==C then A==C.
** <li> If A&lt;B THEN B&gt;A.
** <li> If A&lt;B and B&lt;C then A&lt;C.
** </ol>
**
** If a collating function fails any of the above constraints and that
** collating function is registered and used, then the behavior of SQLite
** is undefined.
**
** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
** with the addition that the xDestroy callback is invoked on pArg when
** the collating function is deleted.
** ^Collating functions are deleted when they are overridden by later
** calls to the collation creation functions or when the
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
);
SQLITE_API int sqlite3_collation_needed16(
  sqlite3*, 
  void*,
  void(*)(void*,sqlite3*,int eTextRep,const void*)
);

#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database.  This routine should be
** called right after sqlite3_open().
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
SQLITE_API int sqlite3_key(
  sqlite3 *db,                   /* Database to be rekeyed */
  const void *pKey, int nKey     /* The key */
);
SQLITE_API int sqlite3_key_v2(
  sqlite3 *db,                   /* Database to be rekeyed */
  const char *zDbName,           /* Name of the database */
  const void *pKey, int nKey     /* The key */
);

/*
** Change the key on an open database.  If the current database is not
** encrypted, this routine will encrypt it.  If pNew==0 or nNew==0, the
** database is decrypted.
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
SQLITE_API int sqlite3_rekey(
  sqlite3 *db,                   /* Database to be rekeyed */
  const void *pKey, int nKey     /* The new key */
);
SQLITE_API int sqlite3_rekey_v2(
  sqlite3 *db,                   /* Database to be rekeyed */
  const char *zDbName,           /* Name of the database */
  const void *pKey, int nKey     /* The new key */
);

/*
** Specify the activation key for a SEE database.  Unless 
** activated, none of the SEE routines will work.
*/
SQLITE_API void sqlite3_activate_see(
  const char *zPassPhrase        /* Activation phrase */
);
#endif

#ifdef SQLITE_ENABLE_CEROD
/*
** Specify the activation key for a CEROD database.  Unless 
** activated, none of the CEROD routines will work.
*/
SQLITE_API void sqlite3_activate_cerod(
  const char *zPassPhrase        /* Activation phrase */







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







5907
5908
5909
5910
5911
5912
5913













































5914
5915
5916
5917
5918
5919
5920
);
SQLITE_API int sqlite3_collation_needed16(
  sqlite3*, 
  void*,
  void(*)(void*,sqlite3*,int eTextRep,const void*)
);














































#ifdef SQLITE_ENABLE_CEROD
/*
** Specify the activation key for a CEROD database.  Unless 
** activated, none of the CEROD routines will work.
*/
SQLITE_API void sqlite3_activate_cerod(
  const char *zPassPhrase        /* Activation phrase */
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936




5937
5938
5939
5940
5941











5942
5943
5944
5945
5946
5947
5948
*/
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);

/*
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
** associated with database N of connection D.  ^The main database file
** has the name "main".  If there is no attached database N on the database
** connection D, or if database N is a temporary or in-memory database, then
** this function will return either a NULL pointer or an empty string.




**
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS].  ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.











*/
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);

/*
** CAPI3REF: Determine if a database is read-only
** METHOD: sqlite3
**







|
|
|


>
>
>
>





>
>
>
>
>
>
>
>
>
>
>







6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
*/
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);

/*
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename
** associated with database N of connection D.
** ^If there is no attached database N on the database
** connection D, or if database N is a temporary or in-memory database, then
** this function will return either a NULL pointer or an empty string.
**
** ^The string value returned by this routine is owned and managed by
** the database connection.  ^The value will be valid until the database N
** is [DETACH]-ed or until the database connection closes.
**
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS].  ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
**
** If the filename pointer returned by this routine is not NULL, then it
** can be used as the filename input parameter to these routines:
** <ul>
** <li> [sqlite3_uri_parameter()]
** <li> [sqlite3_uri_boolean()]
** <li> [sqlite3_uri_int64()]
** <li> [sqlite3_filename_database()]
** <li> [sqlite3_filename_journal()]
** <li> [sqlite3_filename_wal()]
** </ul>
*/
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);

/*
** CAPI3REF: Determine if a database is read-only
** METHOD: sqlite3
**
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099




6100
6101
6102
6103
6104
6105
6106
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). 
** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
** Existing database connections continue use the sharing mode
** that was in effect at the time they were opened.)^
**
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully.  An [error code] is returned otherwise.)^
**
** ^Shared cache is disabled by default. But this might change in
** future releases of SQLite.  Applications that care about shared
** cache setting should set it explicitly.




**
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
** and will always return SQLITE_MISUSE. On those systems, 
** shared cache mode should be enabled per-database connection via 
** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
**
** This interface is threadsafe on processors where writing a







|





|
|
|
>
>
>
>







6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). 
** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
** Existing database connections continue to use the sharing mode
** that was in effect at the time they were opened.)^
**
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully.  An [error code] is returned otherwise.)^
**
** ^Shared cache is disabled by default. It is recommended that it stay
** that way.  In other words, do not use this routine.  This interface
** continues to be provided for historical compatibility, but its use is
** discouraged.  Any use of shared cache is discouraged.  If shared cache
** must be used, it is recommended that shared cache only be enabled for
** individual database connections using the [sqlite3_open_v2()] interface
** with the [SQLITE_OPEN_SHAREDCACHE] flag.
**
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
** and will always return SQLITE_MISUSE. On those systems, 
** shared cache mode should be enabled per-database connection via 
** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
**
** This interface is threadsafe on processors where writing a
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
**
** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
** information about column C of table T in database D
** on [database connection] X.)^  ^The sqlite3_table_column_metadata()
** interface returns SQLITE_OK and fills in the non-NULL pointers in
** the final five arguments with appropriate values if the specified
** column exists.  ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR and if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
** does not.  If the table name parameter T in a call to
** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
** undefined behavior.
**







|







6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
**
** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
** information about column C of table T in database D
** on [database connection] X.)^  ^The sqlite3_table_column_metadata()
** interface returns SQLITE_OK and fills in the non-NULL pointers in
** the final five arguments with appropriate values if the specified
** column exists.  ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
** does not.  If the table name parameter T in a call to
** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
** undefined behavior.
**
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
**
** ^This interface enables or disables both the C-API
** [sqlite3_load_extension()] and the SQL function [load_extension()].
** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
** to enable or disable only the C-API.)^
**
** <b>Security warning:</b> It is recommended that extension loading
** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
** rather than this interface, so the [load_extension()] SQL function
** remains disabled. This will prevent SQL injections from giving attackers
** access to extension loading capabilities.
*/
SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);

/*







|







6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
**
** ^This interface enables or disables both the C-API
** [sqlite3_load_extension()] and the SQL function [load_extension()].
** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
** to enable or disable only the C-API.)^
**
** <b>Security warning:</b> It is recommended that extension loading
** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
** rather than this interface, so the [load_extension()] SQL function
** remains disabled. This will prevent SQL injections from giving attackers
** access to extension loading capabilities.
*/
SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);

/*
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
typedef struct sqlite3_module sqlite3_module;

/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
**
** This structure, sometimes called a "virtual table module", 
** defines the implementation of a [virtual tables].  
** This structure consists mostly of methods for the module.
**
** ^A virtual table module is created by filling in a persistent
** instance of this structure and passing a pointer to that instance
** to [sqlite3_create_module()] or [sqlite3_create_module_v2()].
** ^The registration remains valid until it is replaced by a different
** module or until the [database connection] closes.  The content







|







6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
typedef struct sqlite3_module sqlite3_module;

/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
**
** This structure, sometimes called a "virtual table module", 
** defines the implementation of a [virtual table].  
** This structure consists mostly of methods for the module.
**
** ^A virtual table module is created by filling in a persistent
** instance of this structure and passing a pointer to that instance
** to [sqlite3_create_module()] or [sqlite3_create_module_v2()].
** ^The registration remains valid until it is replaced by a different
** module or until the [database connection] closes.  The content
6551
6552
6553
6554
6555
6556
6557
6558






6559
6560
6561
6562
6563
6564
6565
** non-zero.
**
** The [xBestIndex] method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter.  ^If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv.  ^(If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
** virtual table and is not checked again by SQLite.)^






**
** ^The idxNum and idxPtr values are recorded and passed into the
** [xFilter] method.
** ^[sqlite3_free()] is used to free idxPtr if and only if
** needToFreeIdxPtr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in







|
>
>
>
>
>
>







6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
** non-zero.
**
** The [xBestIndex] method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter.  ^If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv.  ^(If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
** virtual table and might not be checked again by the byte code.)^ ^(The
** aConstraintUsage[].omit flag is an optimization hint. When the omit flag
** is left in its default setting of false, the constraint will always be
** checked separately in byte code.  If the omit flag is change to true, then
** the constraint may or may not be checked in byte code.  In other words,
** when the omit flag is true there is no guarantee that the constraint will
** not be checked again using byte code.)^
**
** ^The idxNum and idxPtr values are recorded and passed into the
** [xFilter] method.
** ^[sqlite3_free()] is used to free idxPtr if and only if
** needToFreeIdxPtr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting 
** to read or write the estimatedRows field are undefined (but are likely 
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for [version 3.9.0] ([dateof:3.9.0]). 
** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/







|







6798
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting 
** to read or write the estimatedRows field are undefined (but are likely 
** to include crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for [version 3.9.0] ([dateof:3.9.0]). 
** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
** these bits.
*/
#define SQLITE_INDEX_SCAN_UNIQUE      1     /* Scan visits at most 1 row */

/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
** These macros defined the allowed values for the
** [sqlite3_index_info].aConstraint[].op field.  Each value represents
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
#define SQLITE_INDEX_CONSTRAINT_EQ         2
#define SQLITE_INDEX_CONSTRAINT_GT         4
#define SQLITE_INDEX_CONSTRAINT_LE         8







|







6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
** these bits.
*/
#define SQLITE_INDEX_SCAN_UNIQUE      1     /* Scan visits at most 1 row */

/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
** These macros define the allowed values for the
** [sqlite3_index_info].aConstraint[].op field.  Each value represents
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
#define SQLITE_INDEX_CONSTRAINT_EQ         2
#define SQLITE_INDEX_CONSTRAINT_GT         4
#define SQLITE_INDEX_CONSTRAINT_LE         8
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
**   <li>  [sqlite3_mutex_held()] </li>
**   <li>  [sqlite3_mutex_notheld()] </li>
** </ul>)^
**
** The only difference is that the public sqlite3_XXX functions enumerated
** above silently ignore any invocations that pass a NULL pointer instead
** of a valid mutex handle. The implementations of the methods defined
** by this structure are not required to handle this case, the results
** of passing a NULL pointer instead of a valid mutex handle are undefined
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
**
** The xMutexInit() method must be threadsafe.  It must be harmless to
** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd().  Second and subsequent calls to







|







7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
**   <li>  [sqlite3_mutex_held()] </li>
**   <li>  [sqlite3_mutex_notheld()] </li>
** </ul>)^
**
** The only difference is that the public sqlite3_XXX functions enumerated
** above silently ignore any invocations that pass a NULL pointer instead
** of a valid mutex handle. The implementations of the methods defined
** by this structure are not required to handle this case. The results
** of passing a NULL pointer instead of a valid mutex handle are undefined
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
**
** The xMutexInit() method must be threadsafe.  It must be harmless to
** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd().  Second and subsequent calls to
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
#define SQLITE_TESTCTRL_PRNG_RESET               7  /* NOT USED */
#define SQLITE_TESTCTRL_BITVEC_TEST              8
#define SQLITE_TESTCTRL_FAULT_INSTALL            9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS     10
#define SQLITE_TESTCTRL_PENDING_BYTE            11
#define SQLITE_TESTCTRL_ASSERT                  12
#define SQLITE_TESTCTRL_ALWAYS                  13
#define SQLITE_TESTCTRL_RESERVE                 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS           15
#define SQLITE_TESTCTRL_ISKEYWORD               16  /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS      17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
#define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19







|







7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
#define SQLITE_TESTCTRL_PRNG_RESET               7  /* NOT USED */
#define SQLITE_TESTCTRL_BITVEC_TEST              8
#define SQLITE_TESTCTRL_FAULT_INSTALL            9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS     10
#define SQLITE_TESTCTRL_PENDING_BYTE            11
#define SQLITE_TESTCTRL_ASSERT                  12
#define SQLITE_TESTCTRL_ALWAYS                  13
#define SQLITE_TESTCTRL_RESERVE                 14  /* NOT USED */
#define SQLITE_TESTCTRL_OPTIMIZATIONS           15
#define SQLITE_TESTCTRL_ISKEYWORD               16  /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS      17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
#define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
** returned value includes allocations that overflowed because they
** where too large (they were larger than the "sz" parameter to
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
** no space was left in the page cache.</dd>)^
**
** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
** <dd>This parameter records the largest memory allocation request
** handed to [pagecache memory allocator].  Only the value returned in the
** *pHighwater parameter to [sqlite3_status()] is of interest.  
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>







|







7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
** returned value includes allocations that overflowed because they
** where too large (they were larger than the "sz" parameter to
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
** no space was left in the page cache.</dd>)^
**
** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
** <dd>This parameter records the largest memory allocation request
** handed to the [pagecache memory allocator].  Only the value returned in the
** *pHighwater parameter to [sqlite3_status()] is of interest.  
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
7802
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
**
** <dl>
** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
** <dd>This parameter returns the number malloc attempts that were 
** satisfied using lookaside memory. Only the high-water value is meaningful;
** the current value is always zero.)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
** <dd>This parameter returns the number malloc attempts that might have
** been satisfied using lookaside memory but failed due to the amount of







|







8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
8021
8022
8023
**
** <dl>
** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
** <dd>This parameter returns the number of malloc attempts that were 
** satisfied using lookaside memory. Only the high-water value is meaningful;
** the current value is always zero.)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
** <dd>This parameter returns the number malloc attempts that might have
** been satisfied using lookaside memory but failed due to the amount of
7884
7885
7886
7887
7888
7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
**
** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt>
** <dd>This parameter returns the number of dirty cache entries that have
** been written to disk in the middle of a transaction due to the page
** cache overflowing. Transactions are more efficient if they are written
** to disk all at once. When pages spill mid-transaction, that introduces
** additional overhead. This parameter can be used help identify
** inefficiencies that can be resolve by increasing the cache size.
** </dd>
**
** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
** <dd>This parameter returns zero for the current value if and only if
** all foreign key constraints (deferred or immediate) have been
** resolved.)^  ^The highwater mark is always 0.
** </dd>







|







8091
8092
8093
8094
8095
8096
8097
8098
8099
8100
8101
8102
8103
8104
8105
**
** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt>
** <dd>This parameter returns the number of dirty cache entries that have
** been written to disk in the middle of a transaction due to the page
** cache overflowing. Transactions are more efficient if they are written
** to disk all at once. When pages spill mid-transaction, that introduces
** additional overhead. This parameter can be used help identify
** inefficiencies that can be resolved by increasing the cache size.
** </dd>
**
** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
** <dd>This parameter returns zero for the current value if and only if
** all foreign key constraints (deferred or immediate) have been
** resolved.)^  ^The highwater mark is always 0.
** </dd>
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982
7983
7984
7985
7986
7987
** to 2147483647.  The number of virtual machine operations can be 
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
**
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
** <dd>^This is the number of times that the prepare statement has been
** automatically regenerated due to schema changes or change to 
** [bound parameters] that might affect the query plan.
**
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
** <dd>^This is the number of times that the prepared statement has
** been run.  A single "run" for the purposes of this counter is one
** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
** The counter is incremented on the first [sqlite3_step()] call of each







|







8180
8181
8182
8183
8184
8185
8186
8187
8188
8189
8190
8191
8192
8193
8194
** to 2147483647.  The number of virtual machine operations can be 
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
**
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
** <dd>^This is the number of times that the prepare statement has been
** automatically regenerated due to schema changes or changes to 
** [bound parameters] that might affect the query plan.
**
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
** <dd>^This is the number of times that the prepared statement has
** been run.  A single "run" for the purposes of this counter is one
** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
** The counter is incremented on the first [sqlite3_step()] call of each
8144
8145
8146
8147
8148
8149
8150
8151
8152
8153
8154
8155
8156
8157
8158
**                 Otherwise return NULL.
** <tr><td> 2 <td> Make every effort to allocate a new page.  Only return
**                 NULL if allocating a new page is effectively impossible.
** </table>
**
** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  SQLite
** will only use a createFlag of 2 after a prior call with a createFlag of 1
** failed.)^  In between the to xFetch() calls, SQLite may
** attempt to unpin one or more cache pages by spilling the content of
** pinned pages to disk and synching the operating system disk cache.
**
** [[the xUnpin() page cache method]]
** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
** as its second argument.  If the third parameter, discard, is non-zero,
** then the page must be evicted from the cache.







|







8351
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361
8362
8363
8364
8365
**                 Otherwise return NULL.
** <tr><td> 2 <td> Make every effort to allocate a new page.  Only return
**                 NULL if allocating a new page is effectively impossible.
** </table>
**
** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  SQLite
** will only use a createFlag of 2 after a prior call with a createFlag of 1
** failed.)^  In between the xFetch() calls, SQLite may
** attempt to unpin one or more cache pages by spilling the content of
** pinned pages to disk and synching the operating system disk cache.
**
** [[the xUnpin() page cache method]]
** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
** as its second argument.  If the third parameter, discard, is non-zero,
** then the page must be evicted from the cache.
8462
8463
8464
8465
8466
8467
8468
8469
8470
8471
8472
8473
8474
8475
8476
** identity of the database connection (the blocking connection) that
** has locked the required resource is stored internally. ^After an 
** application receives an SQLITE_LOCKED error, it may call the
** sqlite3_unlock_notify() method with the blocked connection handle as 
** the first argument to register for a callback that will be invoked
** when the blocking connections current transaction is concluded. ^The
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
** call that concludes the blocking connections transaction.
**
** ^(If sqlite3_unlock_notify() is called in a multi-threaded application,
** there is a chance that the blocking connection will have already
** concluded its transaction by the time sqlite3_unlock_notify() is invoked.
** If this happens, then the specified callback is invoked immediately,
** from within the call to sqlite3_unlock_notify().)^
**







|







8669
8670
8671
8672
8673
8674
8675
8676
8677
8678
8679
8680
8681
8682
8683
** identity of the database connection (the blocking connection) that
** has locked the required resource is stored internally. ^After an 
** application receives an SQLITE_LOCKED error, it may call the
** sqlite3_unlock_notify() method with the blocked connection handle as 
** the first argument to register for a callback that will be invoked
** when the blocking connections current transaction is concluded. ^The
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
** call that concludes the blocking connection's transaction.
**
** ^(If sqlite3_unlock_notify() is called in a multi-threaded application,
** there is a chance that the blocking connection will have already
** concluded its transaction by the time sqlite3_unlock_notify() is invoked.
** If this happens, then the specified callback is invoked immediately,
** from within the call to sqlite3_unlock_notify().)^
**
8500
8501
8502
8503
8504
8505
8506
8507
8508
8509
8510
8511
8512
8513
8514
** When an unlock-notify callback is registered, the application provides a 
** single void* pointer that is passed to the callback when it is invoked.
** However, the signature of the callback function allows SQLite to pass
** it an array of void* context pointers. The first argument passed to
** an unlock-notify callback is a pointer to an array of void* pointers,
** and the second is the number of entries in the array.
**
** When a blocking connections transaction is concluded, there may be
** more than one blocked connection that has registered for an unlock-notify
** callback. ^If two or more such blocked connections have specified the
** same callback function, then instead of invoking the callback function
** multiple times, it is invoked once with the set of void* context pointers
** specified by the blocked connections bundled together into an array.
** This gives the application an opportunity to prioritize any actions 
** related to the set of unblocked database connections.







|







8707
8708
8709
8710
8711
8712
8713
8714
8715
8716
8717
8718
8719
8720
8721
** When an unlock-notify callback is registered, the application provides a 
** single void* pointer that is passed to the callback when it is invoked.
** However, the signature of the callback function allows SQLite to pass
** it an array of void* context pointers. The first argument passed to
** an unlock-notify callback is a pointer to an array of void* pointers,
** and the second is the number of entries in the array.
**
** When a blocking connection's transaction is concluded, there may be
** more than one blocked connection that has registered for an unlock-notify
** callback. ^If two or more such blocked connections have specified the
** same callback function, then instead of invoking the callback function
** multiple times, it is invoked once with the set of void* context pointers
** specified by the blocked connections bundled together into an array.
** This gives the application an opportunity to prioritize any actions 
** related to the set of unblocked database connections.
8848
8849
8850
8851
8852
8853
8854
8855
8856




8857
8858
8859
8860
8861
8862


8863
8864
8865
8866
8867
8868
8869
8870
8871
8872
8873
8874
8875
8876
8877
** This function may be called by either the [xConnect] or [xCreate] method
** of a [virtual table] implementation to configure
** various facets of the virtual table interface.
**
** If this interface is invoked outside the context of an xConnect or
** xCreate virtual table method then the behavior is undefined.
**
** At present, there is only one option that may be configured using
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].)  Further options




** may be added in the future.
*/
SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);

/*
** CAPI3REF: Virtual Table Configuration Options


**
** These macros define the various options to the
** [sqlite3_vtab_config()] interface that [virtual table] implementations
** can use to customize and optimize their behavior.
**
** <dl>
** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]]
** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
** where X is an integer.  If X is zero, then the [virtual table] whose
** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not
** support constraints.  In this configuration (which is the default) if
** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
** statement is rolled back as if [ON CONFLICT | OR ABORT] had been







|
|
>
>
>
>
|





>
>







|







9055
9056
9057
9058
9059
9060
9061
9062
9063
9064
9065
9066
9067
9068
9069
9070
9071
9072
9073
9074
9075
9076
9077
9078
9079
9080
9081
9082
9083
9084
9085
9086
9087
9088
9089
9090
** This function may be called by either the [xConnect] or [xCreate] method
** of a [virtual table] implementation to configure
** various facets of the virtual table interface.
**
** If this interface is invoked outside the context of an xConnect or
** xCreate virtual table method then the behavior is undefined.
**
** In the call sqlite3_vtab_config(D,C,...) the D parameter is the
** [database connection] in which the virtual table is being created and
** which is passed in as the first argument to the [xConnect] or [xCreate]
** method that is invoking sqlite3_vtab_config().  The C parameter is one
** of the [virtual table configuration options].  The presence and meaning
** of parameters after C depend on which [virtual table configuration option]
** is used.
*/
SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);

/*
** CAPI3REF: Virtual Table Configuration Options
** KEYWORDS: {virtual table configuration options} 
** KEYWORDS: {virtual table configuration option}
**
** These macros define the various options to the
** [sqlite3_vtab_config()] interface that [virtual table] implementations
** can use to customize and optimize their behavior.
**
** <dl>
** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]]
** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
** where X is an integer.  If X is zero, then the [virtual table] whose
** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not
** support constraints.  In this configuration (which is the default) if
** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
8892
8893
8894
8895
8896
8897
8898




















8899
8900
8901


8902
8903
8904
8905
8906
8907
8908
** must do so within the [xUpdate] method. If a call to the 
** [sqlite3_vtab_on_conflict()] function indicates that the current ON 
** CONFLICT policy is REPLACE, the virtual table implementation should 
** silently replace the appropriate rows within the xUpdate callback and
** return SQLITE_OK. Or, if this is not possible, it may return
** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT 
** constraint handling.




















** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1



/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
**
** This function may only be called from within a call to the [xUpdate] method
** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],







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



>
>







9105
9106
9107
9108
9109
9110
9111
9112
9113
9114
9115
9116
9117
9118
9119
9120
9121
9122
9123
9124
9125
9126
9127
9128
9129
9130
9131
9132
9133
9134
9135
9136
9137
9138
9139
9140
9141
9142
9143
** must do so within the [xUpdate] method. If a call to the 
** [sqlite3_vtab_on_conflict()] function indicates that the current ON 
** CONFLICT policy is REPLACE, the virtual table implementation should 
** silently replace the appropriate rows within the xUpdate callback and
** return SQLITE_OK. Or, if this is not possible, it may return
** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT 
** constraint handling.
** </dd>
**
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
**
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
** identify that virtual table as being safe to use from within triggers
** and views.  Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker.  Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS          2
#define SQLITE_VTAB_DIRECTONLY         3

/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
**
** This function may only be called from within a call to the [xUpdate] method
** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
8974
8975
8976
8977
8978
8979
8980
8981
8982
8983
8984
8985
8986
8987
8988
8989
8990
8991
8992
8993
8994
8995
8996
8997
8998
8999
9000
9001
9002
9003
9004
9005
9006
9007
9008
9009
9010
9011
9012
9013
9014
**
** When the value returned to V is a string, space to hold that string is
** managed by the prepared statement S and will be automatically freed when
** S is finalized.
**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
** set to the total number of times that the X-th loop has run.</dd>
**
** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
** to the total number of rows examined by all iterations of the X-th loop.</dd>
**
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
** <dd>^The "double" variable pointed to by the T parameter will be set to the
** query planner's estimate for the average number of rows output from each
** iteration of the X-th loop.  If the query planner's estimates was accurate,
** then this value will approximate the quotient NVISIT/NLOOP and the
** product of this value for all prior loops with the same SELECTID will
** be the NLOOP value for the current loop.
**
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
** <dd>^The "const char *" variable pointed to by the T parameter will be set
** to a zero-terminated UTF-8 string containing the name of the index or table
** used for the X-th loop.
**
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
** <dd>^The "const char *" variable pointed to by the T parameter will be set
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
** <dd>^The "int" variable pointed to by the T parameter will be set to the
** "select-id" for the X-th loop.  The select-id identifies which query or
** subquery the loop is part of.  The main query has a select-id of zero.
** The select-id is the same value as is output in the first column
** of an [EXPLAIN QUERY PLAN] query.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP    0







|



|



|







|




|




|







9209
9210
9211
9212
9213
9214
9215
9216
9217
9218
9219
9220
9221
9222
9223
9224
9225
9226
9227
9228
9229
9230
9231
9232
9233
9234
9235
9236
9237
9238
9239
9240
9241
9242
9243
9244
9245
9246
9247
9248
9249
**
** When the value returned to V is a string, space to hold that string is
** managed by the prepared statement S and will be automatically freed when
** S is finalized.
**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
** set to the total number of times that the X-th loop has run.</dd>
**
** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be set
** to the total number of rows examined by all iterations of the X-th loop.</dd>
**
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
** <dd>^The "double" variable pointed to by the V parameter will be set to the
** query planner's estimate for the average number of rows output from each
** iteration of the X-th loop.  If the query planner's estimates was accurate,
** then this value will approximate the quotient NVISIT/NLOOP and the
** product of this value for all prior loops with the same SELECTID will
** be the NLOOP value for the current loop.
**
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the name of the index or table
** used for the X-th loop.
**
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
** <dd>^The "int" variable pointed to by the V parameter will be set to the
** "select-id" for the X-th loop.  The select-id identifies which query or
** subquery the loop is part of.  The main query has a select-id of zero.
** The select-id is the same value as is output in the first column
** of an [EXPLAIN QUERY PLAN] query.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP    0
9855
9856
9857
9858
9859
9860
9861
9862
9863
9864
9865
9866
9867
9868
9869
/*
** CAPI3REF: Set a table filter on a Session Object.
** METHOD: sqlite3_session
**
** The second argument (xFilter) is the "filter callback". For changes to rows 
** in tables that are not attached to the Session object, the filter is called
** to determine whether changes to the table's rows should be tracked or not. 
** If xFilter returns 0, changes is not tracked. Note that once a table is 
** attached, xFilter will not be called again.
*/
SQLITE_API void sqlite3session_table_filter(
  sqlite3_session *pSession,      /* Session object */
  int(*xFilter)(
    void *pCtx,                   /* Copy of third arg to _filter_table() */
    const char *zTab              /* Table name */







|







10090
10091
10092
10093
10094
10095
10096
10097
10098
10099
10100
10101
10102
10103
10104
/*
** CAPI3REF: Set a table filter on a Session Object.
** METHOD: sqlite3_session
**
** The second argument (xFilter) is the "filter callback". For changes to rows 
** in tables that are not attached to the Session object, the filter is called
** to determine whether changes to the table's rows should be tracked or not. 
** If xFilter returns 0, changes are not tracked. Note that once a table is 
** attached, xFilter will not be called again.
*/
SQLITE_API void sqlite3session_table_filter(
  sqlite3_session *pSession,      /* Session object */
  int(*xFilter)(
    void *pCtx,                   /* Copy of third arg to _filter_table() */
    const char *zTab              /* Table name */
10029
10030
10031
10032
10033
10034
10035
10036
10037
10038
10039
10040
10041
10042
10043
** using [sqlite3session_changeset()], then after applying that changeset to 
** database zFrom the contents of the two compatible tables would be 
** identical.
**
** It an error if database zFrom does not exist or does not contain the
** required compatible table.
**
** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
** may be set to point to a buffer containing an English language error 
** message. It is the responsibility of the caller to free this buffer using
** sqlite3_free().
*/
SQLITE_API int sqlite3session_diff(
  sqlite3_session *pSession,







|







10264
10265
10266
10267
10268
10269
10270
10271
10272
10273
10274
10275
10276
10277
10278
** using [sqlite3session_changeset()], then after applying that changeset to 
** database zFrom the contents of the two compatible tables would be 
** identical.
**
** It an error if database zFrom does not exist or does not contain the
** required compatible table.
**
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
** may be set to point to a buffer containing an English language error 
** message. It is the responsibility of the caller to free this buffer using
** sqlite3_free().
*/
SQLITE_API int sqlite3session_diff(
  sqlite3_session *pSession,
10166
10167
10168
10169
10170
10171
10172
10173
10174
10175
10176
10177
10178
10179
10180
#define SQLITE_CHANGESETSTART_INVERT        0x0002


/*
** CAPI3REF: Advance A Changeset Iterator
** METHOD: sqlite3_changeset_iter
**
** This function may only be used with iterators created by function
** [sqlite3changeset_start()]. If it is called on an iterator passed to
** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
** is returned and the call has no effect.
**
** Immediately after an iterator is created by sqlite3changeset_start(), it
** does not point to any change in the changeset. Assuming the changeset
** is not empty, the first call to this function advances the iterator to







|







10401
10402
10403
10404
10405
10406
10407
10408
10409
10410
10411
10412
10413
10414
10415
#define SQLITE_CHANGESETSTART_INVERT        0x0002


/*
** CAPI3REF: Advance A Changeset Iterator
** METHOD: sqlite3_changeset_iter
**
** This function may only be used with iterators created by the function
** [sqlite3changeset_start()]. If it is called on an iterator passed to
** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
** is returned and the call has no effect.
**
** Immediately after an iterator is created by sqlite3changeset_start(), it
** does not point to any change in the changeset. Assuming the changeset
** is not empty, the first call to this function advances the iterator to
10582
10583
10584
10585
10586
10587
10588
10589
10590
10591
10592
10593
10594
10595
10596
10597
**
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
** case, this function fails with SQLITE_SCHEMA. If the input changeset
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
** returned. Or, if an out-of-memory condition occurs during processing, this
** function returns SQLITE_NOMEM. In all cases, if an error occurs the
** final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);

/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup







|
|







10817
10818
10819
10820
10821
10822
10823
10824
10825
10826
10827
10828
10829
10830
10831
10832
**
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
** case, this function fails with SQLITE_SCHEMA. If the input changeset
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
** returned. Or, if an out-of-memory condition occurs during processing, this
** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
** of the final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);

/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
10758
10759
10760
10761
10762
10763
10764
10765
10766
10767
10768
10769
10770
10771
10772
**   This includes the case where the UPDATE operation is attempted after 
**   an earlier call to the conflict handler function returned
**   [SQLITE_CHANGESET_REPLACE].  
** </dl>
**
** It is safe to execute SQL statements, including those that write to the
** table that the callback related to, from within the xConflict callback.
** This can be used to further customize the applications conflict
** resolution strategy.
**
** All changes made by these functions are enclosed in a savepoint transaction.
** If any other error (aside from a constraint failure when attempting to
** write to the target database) occurs, then the savepoint transaction is
** rolled back, restoring the target database to its original state, and an 
** SQLite error code returned.







|







10993
10994
10995
10996
10997
10998
10999
11000
11001
11002
11003
11004
11005
11006
11007
**   This includes the case where the UPDATE operation is attempted after 
**   an earlier call to the conflict handler function returned
**   [SQLITE_CHANGESET_REPLACE].  
** </dl>
**
** It is safe to execute SQL statements, including those that write to the
** table that the callback related to, from within the xConflict callback.
** This can be used to further customize the application's conflict
** resolution strategy.
**
** All changes made by these functions are enclosed in a savepoint transaction.
** If any other error (aside from a constraint failure when attempting to
** write to the target database) occurs, then the savepoint transaction is
** rolled back, restoring the target database to its original state, and an 
** SQLite error code returned.
11068
11069
11070
11071
11072
11073
11074
11075
11076
11077
11078
11079
11080
11081
11082

/*
** CAPI3REF: Rebase a changeset
** EXPERIMENTAL
**
** Argument pIn must point to a buffer containing a changeset nIn bytes
** in size. This function allocates and populates a buffer with a copy
** of the changeset rebased rebased according to the configuration of the
** rebaser object passed as the first argument. If successful, (*ppOut)
** is set to point to the new buffer containing the rebased changeset and 
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
** responsibility of the caller to eventually free the new buffer using
** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
** are set to zero and an SQLite error code returned.
*/







|







11303
11304
11305
11306
11307
11308
11309
11310
11311
11312
11313
11314
11315
11316
11317

/*
** CAPI3REF: Rebase a changeset
** EXPERIMENTAL
**
** Argument pIn must point to a buffer containing a changeset nIn bytes
** in size. This function allocates and populates a buffer with a copy
** of the changeset rebased according to the configuration of the
** rebaser object passed as the first argument. If successful, (*ppOut)
** is set to point to the new buffer containing the rebased changeset and 
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
** responsibility of the caller to eventually free the new buffer using
** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
** are set to zero and an SQLite error code returned.
*/
11476
11477
11478
11479
11480
11481
11482
11483
11484
11485
11486
11487
11488
11489
11490
**   If the query runs to completion without incident, SQLITE_OK is returned.
**   Or, if some error occurs before the query completes or is aborted by
**   the callback, an SQLite error code is returned.
**
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
**   Save the pointer passed as the second argument as the extension functions 
**   "auxiliary data". The pointer may then be retrieved by the current or any
**   future invocation of the same fts5 extension function made as part of
**   the same MATCH query using the xGetAuxdata() API.
**
**   Each extension function is allocated a single auxiliary data slot for
**   each FTS query (MATCH expression). If the extension function is invoked 
**   more than once for a single FTS query, then all invocations share a 







|







11711
11712
11713
11714
11715
11716
11717
11718
11719
11720
11721
11722
11723
11724
11725
**   If the query runs to completion without incident, SQLITE_OK is returned.
**   Or, if some error occurs before the query completes or is aborted by
**   the callback, an SQLite error code is returned.
**
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
**   Save the pointer passed as the second argument as the extension function's 
**   "auxiliary data". The pointer may then be retrieved by the current or any
**   future invocation of the same fts5 extension function made as part of
**   the same MATCH query using the xGetAuxdata() API.
**
**   Each extension function is allocated a single auxiliary data slot for
**   each FTS query (MATCH expression). If the extension function is invoked 
**   more than once for a single FTS query, then all invocations share a 
11718
11719
11720
11721
11722
11723
11724
11725
11726
11727
11728
11729
11730
11731
11732
11733
**   of "first place" within the document set, but not alternative forms
**   such as "1st place". In some applications, it would be better to match
**   all instances of "first place" or "1st place" regardless of which form
**   the user specified in the MATCH query text.
**
**   There are several ways to approach this in FTS5:
**
**   <ol><li> By mapping all synonyms to a single token. In this case, the 
**            In the above example, this means that the tokenizer returns the
**            same token for inputs "first" and "1st". Say that token is in
**            fact "first", so that when the user inserts the document "I won
**            1st place" entries are added to the index for tokens "i", "won",
**            "first" and "place". If the user then queries for '1st + place',
**            the tokenizer substitutes "first" for "1st" and the query works
**            as expected.
**







|
|







11953
11954
11955
11956
11957
11958
11959
11960
11961
11962
11963
11964
11965
11966
11967
11968
**   of "first place" within the document set, but not alternative forms
**   such as "1st place". In some applications, it would be better to match
**   all instances of "first place" or "1st place" regardless of which form
**   the user specified in the MATCH query text.
**
**   There are several ways to approach this in FTS5:
**
**   <ol><li> By mapping all synonyms to a single token. In this case, using
**            the above example, this means that the tokenizer returns the
**            same token for inputs "first" and "1st". Say that token is in
**            fact "first", so that when the user inserts the document "I won
**            1st place" entries are added to the index for tokens "i", "won",
**            "first" and "place". If the user then queries for '1st + place',
**            the tokenizer substitutes "first" for "1st" and the query works
**            as expected.
**
Changes to src/stash.c.
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
      }else{
        int rc;
        if( isLink || isNewLink ){
          rc = -1;
          blob_zero(&b); /* because we reset it later */
          fossil_print("***** Cannot merge symlink %s\n", zNew);
        }else{
          rc = merge_3way(&a, zOPath, &b, &out, 0);
          blob_write_to_file(&out, zNPath);
          blob_reset(&out);
          file_setexe(zNPath, isExec);
        }
        if( rc ){
          fossil_print("CONFLICT %s\n", zNew);
          nConflict++;







|







357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
      }else{
        int rc;
        if( isLink || isNewLink ){
          rc = -1;
          blob_zero(&b); /* because we reset it later */
          fossil_print("***** Cannot merge symlink %s\n", zNew);
        }else{
          rc = merge_3way(&a, zOPath, &b, &out, MERGE_KEEP_FILES);
          blob_write_to_file(&out, zNPath);
          blob_reset(&out);
          file_setexe(zNPath, isExec);
        }
        if( rc ){
          fossil_print("CONFLICT %s\n", zNew);
          nConflict++;
Changes to src/stat.c.
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  }
  db_multi_exec(
    "CREATE TEMP TABLE trans(name TEXT PRIMARY KEY,tabname TEXT)WITHOUT ROWID;"
    "INSERT INTO trans(name,tabname)"
    "   SELECT name, tbl_name FROM repository.sqlite_master;"
    "CREATE TEMP TABLE piechart(amt REAL, label TEXT);"
    "INSERT INTO piechart(amt,label)"
    "  SELECT count(*), "
    "  coalesce((SELECT tabname FROM trans WHERE trans.name=dbstat.name),name)"
    "    FROM dbstat('repository')"
    "   GROUP BY 2 ORDER BY 2;"
  );
  nPageFree = db_int(0, "PRAGMA repository.freelist_count");
  if( nPageFree>0 ){
    db_multi_exec(
      "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')",
      nPageFree







|

|







604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  }
  db_multi_exec(
    "CREATE TEMP TABLE trans(name TEXT PRIMARY KEY,tabname TEXT)WITHOUT ROWID;"
    "INSERT INTO trans(name,tabname)"
    "   SELECT name, tbl_name FROM repository.sqlite_master;"
    "CREATE TEMP TABLE piechart(amt REAL, label TEXT);"
    "INSERT INTO piechart(amt,label)"
    "  SELECT sum(pageno),"
    "  coalesce((SELECT tabname FROM trans WHERE trans.name=dbstat.name),name)"
    "    FROM dbstat('repository',TRUE)"
    "   GROUP BY 2 ORDER BY 2;"
  );
  nPageFree = db_int(0, "PRAGMA repository.freelist_count");
  if( nPageFree>0 ){
    db_multi_exec(
      "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')",
      nPageFree
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  if( g.localOpen ){
    db_multi_exec(
      "DELETE FROM trans;"
      "INSERT INTO trans(name,tabname)"
      "   SELECT name, tbl_name FROM localdb.sqlite_master;"
      "DELETE FROM piechart;"
      "INSERT INTO piechart(amt,label)"
      "  SELECT count(*), "
      " coalesce((SELECT tabname FROM trans WHERE trans.name=dbstat.name),name)"
      "    FROM dbstat('localdb')"
      "   GROUP BY 2 ORDER BY 2;"
    );
    nPageFree = db_int(0, "PRAGMA localdb.freelist_count");
    if( nPageFree>0 ){
      db_multi_exec(
        "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')",
        nPageFree







|

|







630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  if( g.localOpen ){
    db_multi_exec(
      "DELETE FROM trans;"
      "INSERT INTO trans(name,tabname)"
      "   SELECT name, tbl_name FROM localdb.sqlite_master;"
      "DELETE FROM piechart;"
      "INSERT INTO piechart(amt,label)"
      "  SELECT sum(pageno), "
      " coalesce((SELECT tabname FROM trans WHERE trans.name=dbstat.name),name)"
      "    FROM dbstat('localdb',TRUE)"
      "   GROUP BY 2 ORDER BY 2;"
    );
    nPageFree = db_int(0, "PRAGMA localdb.freelist_count");
    if( nPageFree>0 ){
      db_multi_exec(
        "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')",
        nPageFree
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
}

/*
** Gather statistics on artifact types, counts, and sizes.
**
** Only populate the artstat.atype field if the bWithTypes parameter is true.
*/
static void gather_artifact_stats(int bWithTypes){
  static const char zSql[] = 
    @ CREATE TEMP TABLE artstat(
    @   id INTEGER PRIMARY KEY,   -- Corresponds to BLOB.RID
    @   atype TEXT,               -- 'data', 'manifest', 'tag', 'wiki', etc.
    @   isDelta BOOLEAN,          -- true if stored as a delta
    @   szExp,                    -- expanded, uncompressed size
    @   szCmpr                    -- size as stored on disk
    @ );
    @ INSERT INTO artstat(id,atype,isDelta,szExp,szCmpr)
    @    SELECT blob.rid, NULL,
    @           EXISTS(SELECT 1 FROM delta WHERE delta.rid=blob.rid),
    @           size, length(content)
    @      FROM blob
    @     WHERE content IS NOT NULL;
  ;
  static const char zSql2[] = 
    @ UPDATE artstat SET atype='file'
    @  WHERE id IN (SELECT fid FROM mlink)
    @    AND atype IS NULL;
    @ UPDATE artstat SET atype='manifest'
    @  WHERE id IN (SELECT objid FROM event WHERE type='ci') AND atype IS NULL;
    @ UPDATE artstat SET atype='forum'
    @  WHERE id IN (SELECT objid FROM event WHERE type='f') AND atype IS NULL;
    @ UPDATE artstat SET atype='cluster'
    @  WHERE atype IS NULL 
    @    AND id IN (SELECT rid FROM tagxref







|










|

|




|
<







657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682

683
684
685
686
687
688
689
}

/*
** Gather statistics on artifact types, counts, and sizes.
**
** Only populate the artstat.atype field if the bWithTypes parameter is true.
*/
void gather_artifact_stats(int bWithTypes){
  static const char zSql[] = 
    @ CREATE TEMP TABLE artstat(
    @   id INTEGER PRIMARY KEY,   -- Corresponds to BLOB.RID
    @   atype TEXT,               -- 'data', 'manifest', 'tag', 'wiki', etc.
    @   isDelta BOOLEAN,          -- true if stored as a delta
    @   szExp,                    -- expanded, uncompressed size
    @   szCmpr                    -- size as stored on disk
    @ );
    @ INSERT INTO artstat(id,atype,isDelta,szExp,szCmpr)
    @    SELECT blob.rid, NULL,
    @           delta.rid IS NOT NULL,
    @           size, length(content)
    @      FROM blob LEFT JOIN delta ON blob.rid=delta.rid
    @     WHERE content IS NOT NULL;
  ;
  static const char zSql2[] = 
    @ UPDATE artstat SET atype='file'
    @  WHERE +id IN (SELECT fid FROM mlink);

    @ UPDATE artstat SET atype='manifest'
    @  WHERE id IN (SELECT objid FROM event WHERE type='ci') AND atype IS NULL;
    @ UPDATE artstat SET atype='forum'
    @  WHERE id IN (SELECT objid FROM event WHERE type='f') AND atype IS NULL;
    @ UPDATE artstat SET atype='cluster'
    @  WHERE atype IS NULL 
    @    AND id IN (SELECT rid FROM tagxref
764
765
766
767
768
769
770
771
772
773
774

775
776
777
778
779
780
781

  login_check_credentials();

  /* These stats are expensive to compute.  To disable them for
  ** user without check-in privileges, to prevent excessive usage by
  ** robots and random passers-by on the internet
  */
  if( !g.perm.Write ){
    login_needed(g.anon.Admin);
    return;
  }


  style_header("Artifact Statistics");
  style_submenu_element("Repository Stats", "stat");
  style_submenu_element("Artifact List", "bloblist");
  gather_artifact_stats(1);

  db_prepare(&q,







|
|


>







763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781

  login_check_credentials();

  /* These stats are expensive to compute.  To disable them for
  ** user without check-in privileges, to prevent excessive usage by
  ** robots and random passers-by on the internet
  */
  if( !g.perm.Write && !db_get_boolean("artifact_stats_enable",0) ){
    login_needed(g.anon.Write);
    return;
  }
  load_control();

  style_header("Artifact Statistics");
  style_submenu_element("Repository Stats", "stat");
  style_submenu_element("Artifact List", "bloblist");
  gather_artifact_stats(1);

  db_prepare(&q,
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
    int nFull = nTotal - nDelta;
    sqlite3_int64 szCmpr = db_column_int64(&q, 3);
    sqlite3_int64 szExp = db_column_int64(&q, 4);
    @ <tr><td>%h(zType)</td>
    @ <td data-sortkey='%08x(nTotal)' align='right'>%,d(nTotal)</td>
    @ <td data-sortkey='%08x(nFull)' align='right'>%,d(nFull)</td>
    @ <td data-sortkey='%08x(nDelta)' align='right'>%,d(nDelta)</td>
    @ <td data-sortkey='%016x(szCmpr)' align='right'>%,lld(szCmpr)</td>
    @ <td data-sortkey='%016x(szExp)' align='right'>%,lld(szExp)</td>
  }
  @ </tbody></table>
  db_finalize(&q);

  if( db_exists("SELECT 1 FROM artstat WHERE atype='unused'") ){
    @ <h1>Unused Artifacts:</h1>
    db_prepare(&q,







|
|







894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
    int nFull = nTotal - nDelta;
    sqlite3_int64 szCmpr = db_column_int64(&q, 3);
    sqlite3_int64 szExp = db_column_int64(&q, 4);
    @ <tr><td>%h(zType)</td>
    @ <td data-sortkey='%08x(nTotal)' align='right'>%,d(nTotal)</td>
    @ <td data-sortkey='%08x(nFull)' align='right'>%,d(nFull)</td>
    @ <td data-sortkey='%08x(nDelta)' align='right'>%,d(nDelta)</td>
    @ <td data-sortkey='%016llx(szCmpr)' align='right'>%,lld(szCmpr)</td>
    @ <td data-sortkey='%016llx(szExp)' align='right'>%,lld(szExp)</td>
  }
  @ </tbody></table>
  db_finalize(&q);

  if( db_exists("SELECT 1 FROM artstat WHERE atype='unused'") ){
    @ <h1>Unused Artifacts:</h1>
    db_prepare(&q,
Changes to src/style.c.
77
78
79
80
81
82
83





84
85
86
87
88
89
90

91
92
93
94
95
96
97
static int sideboxUsed = 0;

/*
** Ad-unit styles.
*/
static unsigned adUnitFlags = 0;






/*
** Flags for various javascript files needed prior to </body>
*/
static int needHrefJs = 0;      /* href.js */
static int needSortJs = 0;      /* sorttable.js */
static int needGraphJs = 0;     /* graph.js */
static int needCopyBtnJs = 0;   /* copybtn.js */


/*
** Extra JS added to the end of the file.
*/
static Blob blobOnLoad = BLOB_INITIALIZER;

/*







>
>
>
>
>







>







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
static int sideboxUsed = 0;

/*
** Ad-unit styles.
*/
static unsigned adUnitFlags = 0;

/*
** Submenu disable flag
*/
static int submenuEnable = 1;

/*
** Flags for various javascript files needed prior to </body>
*/
static int needHrefJs = 0;      /* href.js */
static int needSortJs = 0;      /* sorttable.js */
static int needGraphJs = 0;     /* graph.js */
static int needCopyBtnJs = 0;   /* copybtn.js */
static int needAccordionJs = 0; /* accordion.js */

/*
** Extra JS added to the end of the file.
*/
static Blob blobOnLoad = BLOB_INITIALIZER;

/*
315
316
317
318
319
320
321







322
323
324
325
326
327
328
    aSubmenuCtrl[nSubmenuCtrl].azChoice = (const char *const *)az;
    aSubmenuCtrl[nSubmenuCtrl].eVisible = STYLE_NORMAL;
    aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
    nSubmenuCtrl++;
  }
}









/*
** Compare two submenu items for sorting purposes
*/
static int submenuCompare(const void *a, const void *b){
  const struct Submenu *A = (const struct Submenu*)a;
  const struct Submenu *B = (const struct Submenu*)b;







>
>
>
>
>
>
>







321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
    aSubmenuCtrl[nSubmenuCtrl].azChoice = (const char *const *)az;
    aSubmenuCtrl[nSubmenuCtrl].eVisible = STYLE_NORMAL;
    aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
    nSubmenuCtrl++;
  }
}

/*
** Disable or enable the submenu
*/
void style_submenu_enable(int onOff){
  submenuEnable = onOff;
}


/*
** Compare two submenu items for sorting purposes
*/
static int submenuCompare(const void *a, const void *b){
  const struct Submenu *A = (const struct Submenu*)a;
  const struct Submenu *B = (const struct Submenu*)b;
471
472
473
474
475
476
477













































478
479
480
481
482
483
484
  if( zNonce[0]==0 ){
    unsigned char zSeed[24];
    sqlite3_randomness(24, zSeed);
    encode16(zSeed,(unsigned char*)zNonce,24);
  }
  return zNonce;
}














































/*
** Default HTML page header text through <body>.  If the repository-specific
** header template lacks a <body> tag, then all of the following is
** prepended.
*/
static char zDfltHeader[] = 







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







484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  if( zNonce[0]==0 ){
    unsigned char zSeed[24];
    sqlite3_randomness(24, zSeed);
    encode16(zSeed,(unsigned char*)zNonce,24);
  }
  return zNonce;
}

/*
** Return the default Content Security Policy (CSP) string.
** If the toHeader argument is true, then also add the
** CSP to the HTTP reply header.
**
** The CSP comes from the "default-csp" setting if it exists and
** is non-empty.  If that setting is an empty string, then the following
** default is used instead:
**
**     default-src 'self' data:;
**     script-src 'self' 'nonce-$nonce';
**     style-src 'self' 'unsafe-inline';
**
** The text '$nonce' is replaced by style_nonce() if and whereever it
** occurs in the input string.
**
** The string returned is obtained from fossil_malloc() and
** should be released by the caller.
*/
char *style_csp(int toHeader){
  static const char zBackupCSP[] = 
   "default-src 'self' data:; "
   "script-src 'self' 'nonce-$nonce'; "
   "style-src 'self' 'unsafe-inline'";
  const char *zFormat = db_get("default-csp","");
  Blob csp;
  char *zNonce;
  char *zCsp;
  if( zFormat[0]==0 ){
    zFormat = zBackupCSP;
  }
  blob_init(&csp, 0, 0);
  while( zFormat[0] && (zNonce = strstr(zFormat,"$nonce"))!=0 ){
    blob_append(&csp, zFormat, (int)(zNonce - zFormat));
    blob_append(&csp, style_nonce(), -1);
    zFormat = zNonce + 6;
  }
  blob_append(&csp, zFormat, -1);
  zCsp = blob_str(&csp);
  if( toHeader ){
    cgi_printf_header("Content-Security-Policy: %s\r\n", zCsp);
  }
  return zCsp;
}

/*
** Default HTML page header text through <body>.  If the repository-specific
** header template lacks a <body> tag, then all of the following is
** prepended.
*/
static char zDfltHeader[] = 
496
497
498
499
500
501
502



503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
;

/*
** Initialize all the default TH1 variables
*/
static void style_init_th1_vars(const char *zTitle){
  const char *zNonce = style_nonce();



  /*
  ** Do not overwrite the TH1 variable "default_csp" if it exists, as this
  ** allows it to be properly overridden via the TH1 setup script (i.e. it
  ** is evaluated before the header is rendered).
  */
  char *zDfltCsp = sqlite3_mprintf("default-src 'self' data: ; "
                                   "script-src 'self' 'nonce-%s' ; "
                                   "style-src 'self' 'unsafe-inline'",
                                   zNonce);
  Th_MaybeStore("default_csp", zDfltCsp);
  sqlite3_free(zDfltCsp);
  Th_Store("nonce", zNonce);
  Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
  Th_Store("project_description", db_get("project-description",""));
  if( zTitle ) Th_Store("title", zTitle);
  Th_Store("baseurl", g.zBaseURL);
  Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
  Th_Store("home", g.zTop);







>
>
>





<
<
<
<

|







554
555
556
557
558
559
560
561
562
563
564
565
566
567
568




569
570
571
572
573
574
575
576
577
;

/*
** Initialize all the default TH1 variables
*/
static void style_init_th1_vars(const char *zTitle){
  const char *zNonce = style_nonce();
  char *zDfltCsp;

  zDfltCsp = style_csp(1);
  /*
  ** Do not overwrite the TH1 variable "default_csp" if it exists, as this
  ** allows it to be properly overridden via the TH1 setup script (i.e. it
  ** is evaluated before the header is rendered).
  */




  Th_MaybeStore("default_csp", zDfltCsp);
  fossil_free(zDfltCsp);
  Th_Store("nonce", zNonce);
  Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
  Th_Store("project_description", db_get("project-description",""));
  if( zTitle ) Th_Store("title", zTitle);
  Th_Store("baseurl", g.zBaseURL);
  Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
  Th_Store("home", g.zTop);
622
623
624
625
626
627
628







629
630
631
632
633
634
635

/*
** Indicate that the table-sorting javascript is needed.
*/
void style_table_sorter(void){
  needSortJs = 1;
}








/*
** Indicate that the timeline graph javascript is needed.
*/
void style_graph_generator(void){
  needGraphJs = 1;
}







>
>
>
>
>
>
>







679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699

/*
** Indicate that the table-sorting javascript is needed.
*/
void style_table_sorter(void){
  needSortJs = 1;
}

/*
** Indicate that the accordion javascript is needed.
*/
void style_accordion(void){
  needAccordionJs = 1;
}

/*
** Indicate that the timeline graph javascript is needed.
*/
void style_graph_generator(void){
  needGraphJs = 1;
}
692
693
694
695
696
697
698



699
700
701
702
703
704
705
  }
  if( needGraphJs ){
    cgi_append_content(builtin_text("graph.js"),-1);
  }
  if( needCopyBtnJs ){
    cgi_append_content(builtin_text("copybtn.js"),-1);
  }



  for(i=0; i<nJsToLoad; i++){
    cgi_append_content(builtin_text(azJsToLoad[i]),-1);
  }
  if( blob_size(&blobOnLoad)>0 ){
    @ window.onload = function(){
    cgi_append_content(blob_buffer(&blobOnLoad), blob_size(&blobOnLoad));
    cgi_append_content("\n}\n", -1);







>
>
>







756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
  }
  if( needGraphJs ){
    cgi_append_content(builtin_text("graph.js"),-1);
  }
  if( needCopyBtnJs ){
    cgi_append_content(builtin_text("copybtn.js"),-1);
  }
  if( needAccordionJs ){
    cgi_append_content(builtin_text("accordion.js"),-1);
  }
  for(i=0; i<nJsToLoad; i++){
    cgi_append_content(builtin_text(azJsToLoad[i]),-1);
  }
  if( blob_size(&blobOnLoad)>0 ){
    @ window.onload = function(){
    cgi_append_content(blob_buffer(&blobOnLoad), blob_size(&blobOnLoad));
    cgi_append_content("\n}\n", -1);
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
  if( !headerHasBeenGenerated ) return;

  /* Go back and put the submenu at the top of the page.  We delay the
  ** creation of the submenu until the end so that we can add elements
  ** to the submenu while generating page text.
  */
  cgi_destination(CGI_HEADER);
  if( nSubmenu+nSubmenuCtrl>0 ){
    int i;
    if( nSubmenuCtrl ){
      @ <form id='f01' method='GET' action='%R/%s(g.zPath)'>
      @ <input type='hidden' name='udc' value='1'>
      cgi_tag_query_parameter("udc");
    }
    @ <div class="submenu">







|







795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  if( !headerHasBeenGenerated ) return;

  /* Go back and put the submenu at the top of the page.  We delay the
  ** creation of the submenu until the end so that we can add elements
  ** to the submenu while generating page text.
  */
  cgi_destination(CGI_HEADER);
  if( submenuEnable && nSubmenu+nSubmenuCtrl>0 ){
    int i;
    if( nSubmenuCtrl ){
      @ <form id='f01' method='GET' action='%R/%s(g.zPath)'>
      @ <input type='hidden' name='udc' value='1'>
      cgi_tag_query_parameter("udc");
    }
    @ <div class="submenu">
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
** For administators, or if the test_env_enable setting is true, then
** details of the request environment are displayed.  Otherwise, just
** the error message is shown.
**
** If zFormat is an empty string, then this is the /test_env page.
*/
void webpage_error(const char *zFormat, ...){
  int i;
  int showAll;
  char *zErr = 0;
  int isAuth = 0;
  char zCap[100];
  static const char *const azCgiVars[] = {
    "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "SCGI",
    "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING",
    "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHENICATION",
    "HTTP_CONNECTION", "HTTP_HOST",
    "HTTP_IF_NONE_MATCH", "HTTP_IF_MODIFIED_SINCE",
    "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED",
    "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",
    "REMOTE_USER", "REQUEST_METHOD",
    "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL",
    "HOME", "FOSSIL_HOME", "USERNAME", "USER", "FOSSIL_USER",
    "SQLITE_TMPDIR", "TMPDIR",
    "TEMP", "TMP", "FOSSIL_VFS",
    "FOSSIL_FORCE_TICKET_MODERATION", "FOSSIL_FORCE_WIKI_MODERATION",
    "FOSSIL_TCL_PATH", "TH1_DELETE_INTERP", "TH1_ENABLE_DOCS",
    "TH1_ENABLE_HOOKS", "TH1_ENABLE_TCL", "REMOTE_HOST",
  };

  login_check_credentials();
  if( g.perm.Admin || g.perm.Setup  || db_get_boolean("test_env_enable",0) ){
    isAuth = 1;
  }
  for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]);
  if( zFormat[0] ){
    va_list ap;
    va_start(ap, zFormat);
    zErr = vmprintf(zFormat, ap);
    va_end(ap);
    style_header("Bad Request");
    @ <h1>/%h(g.zPath): %h(zErr)</h1>







<




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





|







1204
1205
1206
1207
1208
1209
1210

1211
1212
1213
1214

















1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
** For administators, or if the test_env_enable setting is true, then
** details of the request environment are displayed.  Otherwise, just
** the error message is shown.
**
** If zFormat is an empty string, then this is the /test_env page.
*/
void webpage_error(const char *zFormat, ...){

  int showAll;
  char *zErr = 0;
  int isAuth = 0;
  char zCap[100];


















  login_check_credentials();
  if( g.perm.Admin || g.perm.Setup  || db_get_boolean("test_env_enable",0) ){
    isAuth = 1;
  }
  cgi_load_environment();
  if( zFormat[0] ){
    va_list ap;
    va_start(ap, zFormat);
    zErr = vmprintf(zFormat, ap);
    va_end(ap);
    style_header("Bad Request");
    @ <h1>/%h(g.zPath): %h(zErr)</h1>
Changes to src/sync.c.
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  if( g.url.user!=0 && g.url.passwd==0 ){
    g.url.passwd = unobscure(db_get("last-sync-pw", 0));
    g.url.flags |= URL_PROMPT_PW;
    url_prompt_for_password();
  }
  g.zHttpAuth = get_httpauth();
  url_remember();
#if 0 /* Disabled for now */
  if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
    /* When doing an automatic pull, also automatically pull shuns from
    ** the server if pull_shuns is enabled.
    **
    ** TODO:  What happens if the shun list gets really big?
    ** Maybe the shunning list should only be pulled on every 10th
    ** autosync, or something?
    */
    configSync = CONFIGSET_SHUN;
  }
#endif
  if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
  fossil_print("Autosync:  %s\n", g.url.canonical);
  url_enable_proxy("via proxy: ");
  rc = client_sync(flags, configSync, 0);
  return rc;
}

/*
** This routine will try a number of times to perform autosync with a
** 0.5 second sleep between attempts.
**







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



|







59
60
61
62
63
64
65












66
67
68
69
70
71
72
73
74
75
76
  if( g.url.user!=0 && g.url.passwd==0 ){
    g.url.passwd = unobscure(db_get("last-sync-pw", 0));
    g.url.flags |= URL_PROMPT_PW;
    url_prompt_for_password();
  }
  g.zHttpAuth = get_httpauth();
  url_remember();












  if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
  fossil_print("Autosync:  %s\n", g.url.canonical);
  url_enable_proxy("via proxy: ");
  rc = client_sync(flags, configSync, 0, 0);
  return rc;
}

/*
** This routine will try a number of times to perform autosync with a
** 0.5 second sleep between attempts.
**
124
125
126
127
128
129
130
131

132
133
134
135
136
137
138
** and sync.  If a command-line argument is given, that is the URL
** of a server to sync against.  If no argument is given, use the
** most recently synced URL.  Remember the current URL for next time.
*/
static void process_sync_args(
  unsigned *pConfigFlags,      /* Write configuration flags here */
  unsigned *pSyncFlags,        /* Write sync flags here */
  int uvOnly                   /* Special handling flags for UV sync */

){
  const char *zUrl = 0;
  const char *zHttpAuth = 0;
  unsigned configSync = 0;
  unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
  int urlOptional = 0;
  if( find_option("autourl",0,0)!=0 ){







|
>







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
** and sync.  If a command-line argument is given, that is the URL
** of a server to sync against.  If no argument is given, use the
** most recently synced URL.  Remember the current URL for next time.
*/
static void process_sync_args(
  unsigned *pConfigFlags,      /* Write configuration flags here */
  unsigned *pSyncFlags,        /* Write sync flags here */
  int uvOnly,                  /* Special handling flags for UV sync */
  unsigned urlOmitFlags        /* Omit these URL flags */
){
  const char *zUrl = 0;
  const char *zHttpAuth = 0;
  unsigned configSync = 0;
  unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
  int urlOptional = 0;
  if( find_option("autourl",0,0)!=0 ){
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

176
177
178
179
180
181
182
    *pSyncFlags |= SYNC_VERBOSE;
  }
  url_proxy_options();
  clone_ssh_find_options();
  if( !uvOnly ) db_find_and_open_repository(0, 0);
  db_open_config(0, 1);
  if( g.argc==2 ){
    if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
  }else if( g.argc==3 ){
    zUrl = g.argv[2];
  }
  if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL)
   && db_get_boolean("uv-sync",0)
  ){
    *pSyncFlags |= SYNC_UNVERSIONED;
  }

  if( urlFlags & URL_REMEMBER ){
    clone_ssh_db_set_options();
  }
  url_parse(zUrl, urlFlags);
  remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
  url_remember();
  if( g.url.protocol==0 ){







|








>







149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
    *pSyncFlags |= SYNC_VERBOSE;
  }
  url_proxy_options();
  clone_ssh_find_options();
  if( !uvOnly ) db_find_and_open_repository(0, 0);
  db_open_config(0, 1);
  if( g.argc==2 ){
    if( db_get_boolean("auto-shun",0) ) configSync = CONFIGSET_SHUN;
  }else if( g.argc==3 ){
    zUrl = g.argv[2];
  }
  if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL)
   && db_get_boolean("uv-sync",0)
  ){
    *pSyncFlags |= SYNC_UNVERSIONED;
  }
  urlFlags &= ~urlOmitFlags;
  if( urlFlags & URL_REMEMBER ){
    clone_ssh_db_set_options();
  }
  url_parse(zUrl, urlFlags);
  remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
  url_remember();
  if( g.url.protocol==0 ){
198
199
200
201
202
203
204
205
206

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222


223
224
225
226
227
228
229
230
231
232
233
234


235
236
237

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

253
254
255
256
257
258
259
260
261
}

/*
** COMMAND: pull
**
** Usage: %fossil pull ?URL? ?options?
**
** Pull all sharable changes from a remote repository into the local repository.
** Sharable changes include public check-ins, and wiki, ticket, and tech-note

** edits.  Add the --private option to pull private branches.  Use the
** "configuration pull" command to pull website configuration details.
**
** If URL is not specified, then the URL from the most recent clone, push,
** pull, remote-url, or sync command is used.  See "fossil help clone" for
** details on the URL formats.
**
** Options:
**
**   -B|--httpauth USER:PASS    Credentials for the simple HTTP auth protocol,
**                              if required by the remote website
**   --from-parent-project      Pull content from the parent project
**   --ipv4                     Use only IPv4, not IPv6
**   --once                     Do not remember URL for subsequent syncs
**   --proxy PROXY              Use the specified HTTP proxy
**   --private                  Pull private branches too


**   -R|--repository REPO       Local repository to pull into
**   --ssl-identity FILE        Local SSL credentials, if requested by remote
**   --ssh-command SSH          Use SSH as the "ssh" command
**   -v|--verbose               Additional (debugging) output
**   --verily                   Exchange extra information with the remote
**                              to ensure no content is overlooked
**
** See also: clone, config pull, push, remote-url, sync
*/
void pull_cmd(void){
  unsigned configFlags = 0;
  unsigned syncFlags = SYNC_PULL;


  if( find_option("from-parent-project",0,0)!=0 ){
    syncFlags |= SYNC_FROMPARENT;
  }

  process_sync_args(&configFlags, &syncFlags, 0);

  /* We should be done with options.. */
  verify_all_options();

  client_sync(syncFlags, configFlags, 0);
}

/*
** COMMAND: push
**
** Usage: %fossil push ?URL? ?options?
**
** Push all sharable changes from the local repository to a remote repository.
** Sharable changes include public check-ins, and wiki, ticket, and tech-note

** edits.  Use --private to also push private branches.  Use the
** "configuration push" command to push website configuration details.
**
** If URL is not specified, then the URL from the most recent clone, push,
** pull, remote-url, or sync command is used.  See "fossil help clone" for
** details on the URL formats.
**
** Options:
**







|
|
>
|













<

>
>












>
>



>
|




|







|
|
>
|
|







188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
}

/*
** COMMAND: pull
**
** Usage: %fossil pull ?URL? ?options?
**
** Pull all sharable changes from a remote repository into the local
** repository.  Sharable changes include public check-ins, edits to
** wiki pages, tickets, and tech-notes, as well as forum content.  Add
** the --private option to pull private branches.  Use the
** "configuration pull" command to pull website configuration details.
**
** If URL is not specified, then the URL from the most recent clone, push,
** pull, remote-url, or sync command is used.  See "fossil help clone" for
** details on the URL formats.
**
** Options:
**
**   -B|--httpauth USER:PASS    Credentials for the simple HTTP auth protocol,
**                              if required by the remote website
**   --from-parent-project      Pull content from the parent project
**   --ipv4                     Use only IPv4, not IPv6
**   --once                     Do not remember URL for subsequent syncs

**   --private                  Pull private branches too
**   --project-code CODE        Use CODE as the project code
**   --proxy PROXY              Use the specified HTTP proxy
**   -R|--repository REPO       Local repository to pull into
**   --ssl-identity FILE        Local SSL credentials, if requested by remote
**   --ssh-command SSH          Use SSH as the "ssh" command
**   -v|--verbose               Additional (debugging) output
**   --verily                   Exchange extra information with the remote
**                              to ensure no content is overlooked
**
** See also: clone, config pull, push, remote-url, sync
*/
void pull_cmd(void){
  unsigned configFlags = 0;
  unsigned syncFlags = SYNC_PULL;
  unsigned urlOmitFlags = 0;
  const char *zAltPCode = find_option("project-code",0,1);
  if( find_option("from-parent-project",0,0)!=0 ){
    syncFlags |= SYNC_FROMPARENT;
  }
  if( zAltPCode ) urlOmitFlags = URL_REMEMBER;
  process_sync_args(&configFlags, &syncFlags, 0, urlOmitFlags);

  /* We should be done with options.. */
  verify_all_options();

  client_sync(syncFlags, configFlags, 0, zAltPCode);
}

/*
** COMMAND: push
**
** Usage: %fossil push ?URL? ?options?
**
** Push all sharable changes from the local repository to a remote
** repository.  Sharable changes include public check-ins, edits to
** wiki pages, tickets, and tech-notes, as well as forum content.  Use
** --private to also push private branches.  Use the "configuration
** push" command to push website configuration details.
**
** If URL is not specified, then the URL from the most recent clone, push,
** pull, remote-url, or sync command is used.  See "fossil help clone" for
** details on the URL formats.
**
** Options:
**
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
**                              to ensure no content is overlooked
**
** See also: clone, config push, pull, remote-url, sync
*/
void push_cmd(void){
  unsigned configFlags = 0;
  unsigned syncFlags = SYNC_PUSH;
  process_sync_args(&configFlags, &syncFlags, 0);

  /* We should be done with options.. */
  verify_all_options();

  if( db_get_boolean("dont-push",0) ){
    fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
  }
  client_sync(syncFlags, 0, 0);
}


/*
** COMMAND: sync
**
** Usage: %fossil sync ?URL? ?options?







|







|







269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
**                              to ensure no content is overlooked
**
** See also: clone, config push, pull, remote-url, sync
*/
void push_cmd(void){
  unsigned configFlags = 0;
  unsigned syncFlags = SYNC_PUSH;
  process_sync_args(&configFlags, &syncFlags, 0, 0);

  /* We should be done with options.. */
  verify_all_options();

  if( db_get_boolean("dont-push",0) ){
    fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
  }
  client_sync(syncFlags, 0, 0, 0);
}


/*
** COMMAND: sync
**
** Usage: %fossil sync ?URL? ?options?
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
*/
void sync_cmd(void){
  unsigned configFlags = 0;
  unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
  if( find_option("unversioned","u",0)!=0 ){
    syncFlags |= SYNC_UNVERSIONED;
  }
  process_sync_args(&configFlags, &syncFlags, 0);

  /* We should be done with options.. */
  verify_all_options();

  if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
  client_sync(syncFlags, configFlags, 0);
  if( (syncFlags & SYNC_PUSH)==0 ){
    fossil_warning("pull only: the 'dont-push' option is set");
  }
}

/*
** Handle the "fossil unversioned sync" and "fossil unversioned revert"
** commands.
*/
void sync_unversioned(unsigned syncFlags){
  unsigned configFlags = 0;
  (void)find_option("uv-noop",0,0);
  process_sync_args(&configFlags, &syncFlags, 1);
  verify_all_options();
  client_sync(syncFlags, 0, 0);
}

/*
** COMMAND: remote-url
**
** Usage: %fossil remote-url ?URL|off?
**







|





|












|

|







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
*/
void sync_cmd(void){
  unsigned configFlags = 0;
  unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
  if( find_option("unversioned","u",0)!=0 ){
    syncFlags |= SYNC_UNVERSIONED;
  }
  process_sync_args(&configFlags, &syncFlags, 0, 0);

  /* We should be done with options.. */
  verify_all_options();

  if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
  client_sync(syncFlags, configFlags, 0, 0);
  if( (syncFlags & SYNC_PUSH)==0 ){
    fossil_warning("pull only: the 'dont-push' option is set");
  }
}

/*
** Handle the "fossil unversioned sync" and "fossil unversioned revert"
** commands.
*/
void sync_unversioned(unsigned syncFlags){
  unsigned configFlags = 0;
  (void)find_option("uv-noop",0,0);
  process_sync_args(&configFlags, &syncFlags, 1, 0);
  verify_all_options();
  client_sync(syncFlags, 0, 0, 0);
}

/*
** COMMAND: remote-url
**
** Usage: %fossil remote-url ?URL|off?
**
Changes to src/tag.c.
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
    }
  }
  if( zCol ){
    db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
                  zCol, zValue, rid);
    if( tagid==TAG_COMMENT ){
      char *zCopy = mprintf("%s", zValue);
      wiki_extract_links(zCopy, rid, 0, mtime, 1, WIKI_INLINE);
      free(zCopy);
    }
  }
  if( tagid==TAG_DATE ){
    db_multi_exec("UPDATE event "
                  "   SET mtime=julianday(%Q),"
                  "       omtime=coalesce(omtime,mtime)"







|







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
    }
  }
  if( zCol ){
    db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
                  zCol, zValue, rid);
    if( tagid==TAG_COMMENT ){
      char *zCopy = mprintf("%s", zValue);
      backlink_extract(zCopy, 0, rid, BKLNK_COMMENT, mtime, 1);
      free(zCopy);
    }
  }
  if( tagid==TAG_DATE ){
    db_multi_exec("UPDATE event "
                  "   SET mtime=julianday(%Q),"
                  "       omtime=coalesce(omtime,mtime)"
421
422
423
424
425
426
427

428
429
430
431
432
433
434
**         List all tags, or if CHECK-IN is supplied, list
**         all tags and their values for CHECK-IN.  The tagtype option
**         takes one of: propagated, singleton, cancel.
**
**         Options:
**           --raw           List tags raw names of tags
**           --tagtype TYPE  List only tags of type TYPE

**
** The option --raw allows the manipulation of all types of tags
** used for various internal purposes in fossil. It also shows
** "cancel" tags for the "find" and "list" subcommands. You should
** not use this option to make changes unless you are sure what
** you are doing.
**







>







421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
**         List all tags, or if CHECK-IN is supplied, list
**         all tags and their values for CHECK-IN.  The tagtype option
**         takes one of: propagated, singleton, cancel.
**
**         Options:
**           --raw           List tags raw names of tags
**           --tagtype TYPE  List only tags of type TYPE
**           -v|--inverse    Inverse the meaning of --tagtype TYPE.
**
** The option --raw allows the manipulation of all types of tags
** used for various internal purposes in fossil. It also shows
** "cancel" tags for the "find" and "list" subcommands. You should
** not use this option to make changes unless you are sure what
** you are doing.
**
546
547
548
549
550
551
552
553
554

555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
        db_finalize(&q);
      }
    }
  }else

  if(( strncmp(g.argv[2],"list",n)==0 )||( strncmp(g.argv[2],"ls",n)==0 )){
    Stmt q;
    int fRaw = find_option("raw","",0)!=0;
    const char *zTagType = find_option("tagtype","t",1);

    int nTagType = fRaw ? -1 : 0;
    if( zTagType!=0 ){
      int l = strlen(zTagType);
      if( strncmp(zTagType,"cancel",l)==0 ){
        nTagType = 0;
      }else if( strncmp(zTagType,"singleton",l)==0 ){ 
        nTagType = 1;
      }else if( strncmp(zTagType,"propagated",l)==0 ){ 
        nTagType = 2;
      }else{
        fossil_fatal("unrecognized tag type");
      }
    }
    if( g.argc==3 ){
      db_prepare(&q,
        "SELECT tagname FROM tag"
        " WHERE EXISTS(SELECT 1 FROM tagxref"
        "               WHERE tagid=tag.tagid"
        "                 AND tagtype%c%d)"
        " ORDER BY tagname",
        zTagType!=0 ? '=' : '>',
        nTagType
      );
      while( db_step(&q)==SQLITE_ROW ){
        const char *zName = db_column_text(&q, 0);
        if( fRaw ){
          fossil_print("%s\n", zName);
        }else if( strncmp(zName, "sym-", 4)==0 ){
          fossil_print("%s\n", &zName[4]);
        }
      }
      db_finalize(&q);
    }else if( g.argc==4 ){
      int rid = name_to_rid(g.argv[3]);
      db_prepare(&q,
        "SELECT tagname, value FROM tagxref, tag"
        " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
        "   AND tagtype%c%d"
        " ORDER BY tagname",
        rid,
        zTagType!=0 ? '=' : '>',
        nTagType
      );
      while( db_step(&q)==SQLITE_ROW ){
        const char *zName = db_column_text(&q, 0);
        const char *zValue = db_column_text(&q, 1);
        if( fRaw==0 ){
          if( strncmp(zName, "sym-", 4)!=0 ) continue;







|

>


















|

|
















|


|







547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
        db_finalize(&q);
      }
    }
  }else

  if(( strncmp(g.argv[2],"list",n)==0 )||( strncmp(g.argv[2],"ls",n)==0 )){
    Stmt q;
    const int fRaw = find_option("raw","",0)!=0;
    const char *zTagType = find_option("tagtype","t",1);
    const int fInverse = find_option("inverse","v",0)!=0;
    int nTagType = fRaw ? -1 : 0;
    if( zTagType!=0 ){
      int l = strlen(zTagType);
      if( strncmp(zTagType,"cancel",l)==0 ){
        nTagType = 0;
      }else if( strncmp(zTagType,"singleton",l)==0 ){ 
        nTagType = 1;
      }else if( strncmp(zTagType,"propagated",l)==0 ){ 
        nTagType = 2;
      }else{
        fossil_fatal("unrecognized tag type");
      }
    }
    if( g.argc==3 ){
      db_prepare(&q,
        "SELECT tagname FROM tag"
        " WHERE EXISTS(SELECT 1 FROM tagxref"
        "               WHERE tagid=tag.tagid"
        "                 AND tagtype%s%d)"
        " ORDER BY tagname",
        zTagType!=0 ? (fInverse!=0?"<>":"=") : ">"/*safe-for-%s*/,
        nTagType
      );
      while( db_step(&q)==SQLITE_ROW ){
        const char *zName = db_column_text(&q, 0);
        if( fRaw ){
          fossil_print("%s\n", zName);
        }else if( strncmp(zName, "sym-", 4)==0 ){
          fossil_print("%s\n", &zName[4]);
        }
      }
      db_finalize(&q);
    }else if( g.argc==4 ){
      int rid = name_to_rid(g.argv[3]);
      db_prepare(&q,
        "SELECT tagname, value FROM tagxref, tag"
        " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
        "   AND tagtype%s%d"
        " ORDER BY tagname",
        rid,
        zTagType!=0 ? (fInverse!=0?"<>":"=") : ">"/*safe-for-%s*/,
        nTagType
      );
      while( db_step(&q)==SQLITE_ROW ){
        const char *zName = db_column_text(&q, 0);
        const char *zValue = db_column_text(&q, 1);
        if( fRaw==0 ){
          if( strncmp(zName, "sym-", 4)!=0 ) continue;
Changes to src/th_main.c.
527
528
529
530
531
532
533



























534
535
536
537
538
539
540
){
  if( argc!=1 ){
    return Th_WrongNumArgs(interp, "verifyCsrf");
  }
  login_verify_csrf_secret();
  return TH_OK;
}




























/*
** TH1 command: markdown STRING
**
** Renders the input string as markdown.  The result is a two-element list.
** The first element is the text-only title string.  The second element
** contains the body, rendered as HTML.







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







527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
){
  if( argc!=1 ){
    return Th_WrongNumArgs(interp, "verifyCsrf");
  }
  login_verify_csrf_secret();
  return TH_OK;
}

/*
** TH1 command: verifyLogin
**
** Returns non-zero if the specified user name and password represent a
** valid login for the repository.
*/
static int verifyLoginCmd(
  Th_Interp *interp,
  void *p,
  int argc,
  const char **argv,
  int *argl
){
  const char *zUser;
  const char *zPass;
  int uid;
  if( argc!=3 ){
    return Th_WrongNumArgs(interp, "verifyLogin userName password");
  }
  zUser = argv[1];
  zPass = argv[2];
  uid = login_search_uid(&zUser, zPass);
  Th_SetResultInt(interp, uid!=0);
  if( uid==0 ) sqlite3_sleep(100);
  return TH_OK;
}

/*
** TH1 command: markdown STRING
**
** Renders the input string as markdown.  The result is a two-element list.
** The first element is the text-only title string.  The second element
** contains the body, rendered as HTML.
2109
2110
2111
2112
2113
2114
2115

2116
2117
2118
2119
2120
2121
2122
    {"styleScript",   styleScriptCmd,       0},
    {"tclReady",      tclReadyCmd,          0},
    {"trace",         traceCmd,             0},
    {"stime",         stimeCmd,             0},
    {"unversioned",   unversionedCmd,       0},
    {"utime",         utimeCmd,             0},
    {"verifyCsrf",    verifyCsrfCmd,        0},

    {"wiki",          wikiCmd,              (void*)&aFlags[0]},
    {0, 0, 0}
  };
  if( g.thTrace ){
    Th_Trace("th1-init 0x%x => 0x%x<br />\n", g.th1Flags, flags);
  }
  if( needConfig ){







>







2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
    {"styleScript",   styleScriptCmd,       0},
    {"tclReady",      tclReadyCmd,          0},
    {"trace",         traceCmd,             0},
    {"stime",         stimeCmd,             0},
    {"unversioned",   unversionedCmd,       0},
    {"utime",         utimeCmd,             0},
    {"verifyCsrf",    verifyCsrfCmd,        0},
    {"verifyLogin",   verifyLoginCmd,       0},
    {"wiki",          wikiCmd,              (void*)&aFlags[0]},
    {0, 0, 0}
  };
  if( g.thTrace ){
    Th_Trace("th1-init 0x%x => 0x%x<br />\n", g.th1Flags, flags);
  }
  if( needConfig ){
Changes to src/timeline.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

/*
** Add an appropriate tag to the output if "rid" is unpublished (private)
*/
#define UNPUB_TAG "<em>(unpublished)</em>"
void tag_private_status(int rid){
  if( content_is_private(rid) ){
    cgi_printf("%s", UNPUB_TAG);
  }
}

/*
** Generate a hyperlink to a version.
*/
void hyperlink_to_uuid(const char *zUuid){







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

/*
** Add an appropriate tag to the output if "rid" is unpublished (private)
*/
#define UNPUB_TAG "<em>(unpublished)</em>"
void tag_private_status(int rid){
  if( content_is_private(rid) ){
    cgi_printf(" %s", UNPUB_TAG);
  }
}

/*
** Generate a hyperlink to a version.
*/
void hyperlink_to_uuid(const char *zUuid){
112
113
114
115
116
117
118



119
120
121
122
123
124
125
#define TIMELINE_CLASSIC  0x0010000 /* Use the "classic" view style */
#define TIMELINE_VIEWS    0x001f000 /* Mask for all of the view styles */
#define TIMELINE_NOSCROLL 0x0100000 /* Don't scroll to the selection */
#define TIMELINE_FILEDIFF 0x0200000 /* Show File differences, not ckin diffs */
#define TIMELINE_CHPICK   0x0400000 /* Show cherrypick merges */
#define TIMELINE_FILLGAPS 0x0800000 /* Dotted lines for missing nodes */
#define TIMELINE_XMERGE   0x1000000 /* Omit merges from off-graph nodes */



#endif

/*
** Hash a string and use the hash to determine a background color.
*/
char *hash_color(const char *z){
  int i;                       /* Loop counter */







>
>
>







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#define TIMELINE_CLASSIC  0x0010000 /* Use the "classic" view style */
#define TIMELINE_VIEWS    0x001f000 /* Mask for all of the view styles */
#define TIMELINE_NOSCROLL 0x0100000 /* Don't scroll to the selection */
#define TIMELINE_FILEDIFF 0x0200000 /* Show File differences, not ckin diffs */
#define TIMELINE_CHPICK   0x0400000 /* Show cherrypick merges */
#define TIMELINE_FILLGAPS 0x0800000 /* Dotted lines for missing nodes */
#define TIMELINE_XMERGE   0x1000000 /* Omit merges from off-graph nodes */
#define TIMELINE_NOTKT    0x2000000 /* Omit extra ticket classes */
#define TIMELINE_FORUMTXT 0x4000000 /* Render all forum messages */
#define TIMELINE_REFS     0x8000000 /* Output intended for References tab */
#endif

/*
** Hash a string and use the hash to determine a background color.
*/
char *hash_color(const char *z){
  int i;                       /* Loop counter */
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
**    0.  rid
**    1.  UUID
**    2.  Date/Time
**    3.  Comment string
**    4.  User
**    5.  True if is a leaf
**    6.  background color
**    7.  type ("ci", "w", "t", "e", "g", "div")
**    8.  list of symbolic tags.
**    9.  tagid for ticket or wiki or event
**   10.  Short comment to user for repeated tickets and wiki
*/
void www_print_timeline(
  Stmt *pQuery,            /* Query to implement the timeline */
  int tmFlags,             /* Flags controlling display behavior */







|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
**    0.  rid
**    1.  UUID
**    2.  Date/Time
**    3.  Comment string
**    4.  User
**    5.  True if is a leaf
**    6.  background color
**    7.  type ("ci", "w", "t", "e", "g", "f", "div")
**    8.  list of symbolic tags.
**    9.  tagid for ticket or wiki or event
**   10.  Short comment to user for repeated tickets and wiki
*/
void www_print_timeline(
  Stmt *pQuery,            /* Query to implement the timeline */
  int tmFlags,             /* Flags controlling display behavior */
322
323
324
325
326
327
328

329
330
331
332
333
334
335
    const char *zBr = 0;      /* Branch */
    int commentColumn = 3;    /* Column containing comment text */
    int modPending;           /* Pending moderation */
    char *zDateLink;          /* URL for the link on the timestamp */
    int drawDetailEllipsis;   /* True to show ellipsis in place of detail */
    int gidx = 0;             /* Graph row identifier */
    int isSelectedOrCurrent = 0;  /* True if current row is selected */

    char zTime[20];

    if( zDate==0 ){
      zDate = "YYYY-MM-DD HH:MM:SS";  /* Something wrong with the repo */
    }
    modPending = moderation_pending(rid);
    if( tagid ){







>







325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
    const char *zBr = 0;      /* Branch */
    int commentColumn = 3;    /* Column containing comment text */
    int modPending;           /* Pending moderation */
    char *zDateLink;          /* URL for the link on the timestamp */
    int drawDetailEllipsis;   /* True to show ellipsis in place of detail */
    int gidx = 0;             /* Graph row identifier */
    int isSelectedOrCurrent = 0;  /* True if current row is selected */
    const char *zExtraClass = "";
    char zTime[20];

    if( zDate==0 ){
      zDate = "YYYY-MM-DD HH:MM:SS";  /* Something wrong with the repo */
    }
    modPending = moderation_pending(rid);
    if( tagid ){
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
      @ <tr class="timelineSelected timelineSecondary">
      isSelectedOrCurrent = 1;
    }else if( rid==vid ){
      @ <tr class="timelineCurrent">
      isSelectedOrCurrent = 1;
    }else {
      @ <tr>













    }
    if( zType[0]=='e' && tagid ){
      if( bTimestampLinksToInfo ){
        char *zId;
        zId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d",
                          tagid);
        zDateLink = href("%R/technote/%s",zId);
        free(zId);
      }else{
        zDateLink = href("%R/timeline?c=%t",zDate);
      }
    }else if( zUuid ){
      if( bTimestampLinksToInfo ){
        zDateLink = chref("timelineHistLink", "%R/info/%!S", zUuid);
      }else{
        zDateLink = chref("timelineHistLink", "%R/timeline?c=%!S", zUuid);
      }
    }else{
      zDateLink = mprintf("<a>");
    }
    @ <td class="timelineTime">%z(zDateLink)%s(zTime)</a></td>
    @ <td class="timelineGraph">
    if( tmFlags & TIMELINE_UCOLOR )  zBgClr = zUser ? hash_color(zUser) : 0;







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









|





|







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
      @ <tr class="timelineSelected timelineSecondary">
      isSelectedOrCurrent = 1;
    }else if( rid==vid ){
      @ <tr class="timelineCurrent">
      isSelectedOrCurrent = 1;
    }else {
      @ <tr>
    }
    if( zType[0]=='t' && tagid && (tmFlags & TIMELINE_NOTKT)==0 ){
      char *zTktid = db_text(0, "SELECT substr(tagname,5) FROM tag"
                                " WHERE tagid=%d", tagid);
      if( zTktid ){
        int isClosed = 0;
        if( is_ticket(zTktid, &isClosed) && isClosed ){
          zExtraClass = " tktTlClosed";
        }else{
          zExtraClass = " tktTlOpen";
        }
        fossil_free(zTktid);
      }   
    }
    if( zType[0]=='e' && tagid ){
      if( bTimestampLinksToInfo ){
        char *zId;
        zId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d",
                          tagid);
        zDateLink = href("%R/technote/%s",zId);
        free(zId);
      }else{
        zDateLink = href("%R/timeline?c=%t&y=a",zDate);
      }
    }else if( zUuid ){
      if( bTimestampLinksToInfo ){
        zDateLink = chref("timelineHistLink", "%R/info/%!S", zUuid);
      }else{
        zDateLink = chref("timelineHistLink", "%R/timeline?c=%!S&y=a", zUuid);
      }
    }else{
      zDateLink = mprintf("<a>");
    }
    @ <td class="timelineTime">%z(zDateLink)%s(zTime)</a></td>
    @ <td class="timelineGraph">
    if( tmFlags & TIMELINE_UCOLOR )  zBgClr = zUser ? hash_color(zUser) : 0;
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
      ** not actually draw anything on the graph, but it will set the
      ** background color of the timeline entry */
      gidx = graph_add_row(pGraph, rid, -1, 0, 0, zBr, zBgClr, zUuid, 0);
      @ <div id="m%d(gidx)" class="tl-nodemark"></div>
    }
    @</td>
    if( !isSelectedOrCurrent ){
      @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
    }else{
      @ <td class="timeline%s(zStyle)Cell">
    }
    if( pGraph && zType[0]!='c' ){
      @ &bull;
    }
    if( modPending ){
      @ <span class="modpending">(Awaiting Moderator Approval)</span>
    }







|

|







501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
      ** not actually draw anything on the graph, but it will set the
      ** background color of the timeline entry */
      gidx = graph_add_row(pGraph, rid, -1, 0, 0, zBr, zBgClr, zUuid, 0);
      @ <div id="m%d(gidx)" class="tl-nodemark"></div>
    }
    @</td>
    if( !isSelectedOrCurrent ){
      @ <td class="timeline%s(zStyle)Cell%s(zExtraClass)" id='mc%d(gidx)'>
    }else{
      @ <td class="timeline%s(zStyle)Cell%s(zExtraClass)">
    }
    if( pGraph && zType[0]!='c' ){
      @ &bull;
    }
    if( modPending ){
      @ <span class="modpending">(Awaiting Moderator Approval)</span>
    }
541
542
543
544
545
546
547
548















549

550



551
552
553
554
555
556
557
          @ (%d(rid))
        }
      }
    }
    if( zType[0]!='c' ){
      /* Comments for anything other than a check-in are generated by
      ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
      if( zType[0]=='w' ) wiki_hyperlink_override(zUuid);















      wiki_convert(&comment, 0, WIKI_INLINE);

      wiki_hyperlink_override(0);



    }else{
      if( bCommentGitStyle ){
        /* Truncate comment at first blank line */
        int ii, jj;
        int n = blob_size(&comment);
        char *z = blob_str(&comment);
        for(ii=0; ii<n; ii++){







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







558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
          @ (%d(rid))
        }
      }
    }
    if( zType[0]!='c' ){
      /* Comments for anything other than a check-in are generated by
      ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
      if( zType[0]=='w' ){
        const char *zCom = blob_str(&comment);
        char *zWiki;
        wiki_hyperlink_override(zUuid);
        if( (tmFlags & TIMELINE_REFS)!=0
         && (zWiki = strstr(zCom,"wiki"))!=0
        ){
          /* The TIMELINE_REFS flag causes timeline comments of the
          ** form "Changes to wiki..." or "Added wiki" to be changed
          ** into just "Wiki..." */
          Blob rcom;
          blob_init(&rcom, 0, 0);
          blob_appendf(&rcom, "W%s", zWiki+1);
          wiki_convert(&rcom, 0, WIKI_INLINE);
          blob_reset(&rcom);
        }else{
          wiki_convert(&comment, 0, WIKI_INLINE);
        }
        wiki_hyperlink_override(0);
      }else{
        wiki_convert(&comment, 0, WIKI_INLINE);
      }
    }else{
      if( bCommentGitStyle ){
        /* Truncate comment at first blank line */
        int ii, jj;
        int n = blob_size(&comment);
        char *z = blob_str(&comment);
        for(ii=0; ii<n; ii++){
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
    */
    if( drawDetailEllipsis ){
      @ <span class='timelineEllipsis' id='ellipsis-%d(rid)' \
      @ data-id='%d(rid)'>...</span>
    }
    if( tmFlags & TIMELINE_COLUMNAR ){
      if( !isSelectedOrCurrent ){
        @ <td class="timelineDetailCell" id='md%d(gidx)'>
      }else{
        @ <td class="timelineDetailCell">
      }
    }
    if( tmFlags & TIMELINE_COMPACT ){
      cgi_printf("<span class='clutter' id='detail-%d'>",rid);
    }
    cgi_printf("<span class='timeline%sDetail'>", zStyle);
    if( (tmFlags & (TIMELINE_CLASSIC|TIMELINE_VERBOSE|TIMELINE_COMPACT))!=0 ){







|

|







618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
    */
    if( drawDetailEllipsis ){
      @ <span class='timelineEllipsis' id='ellipsis-%d(rid)' \
      @ data-id='%d(rid)'>...</span>
    }
    if( tmFlags & TIMELINE_COLUMNAR ){
      if( !isSelectedOrCurrent ){
        @ <td class="timelineDetailCell%s(zExtraClass)" id='md%d(gidx)'>
      }else{
        @ <td class="timelineDetailCell%s(zExtraClass)">
      }
    }
    if( tmFlags & TIMELINE_COMPACT ){
      cgi_printf("<span class='clutter' id='detail-%d'>",rid);
    }
    cgi_printf("<span class='timeline%sDetail'>", zStyle);
    if( (tmFlags & (TIMELINE_CLASSIC|TIMELINE_VERBOSE|TIMELINE_COMPACT))!=0 ){
613
614
615
616
617
618
619
620

621
622
623
624


625



626
627
628
629
630
631
632
        cgi_printf("check-in:&nbsp;%z%S</a> ",href("%R/info/%!S",zUuid),zUuid);
      }else if( zType[0]=='e' && tagid ){
        cgi_printf("technote:&nbsp;");
        hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
      }else{
        cgi_printf("artifact:&nbsp;%z%S</a> ",href("%R/info/%!S",zUuid),zUuid);
      }
    }else if( zType[0]=='g' || zType[0]=='w' || zType[0]=='t' || zType[0]=='f'){

      cgi_printf("artifact:&nbsp;%z%S</a> ",href("%R/info/%!S",zUuid),zUuid);
    }

    if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){


      char *zLink = mprintf("%R/timeline?u=%h&c=%t&y=a", zDispUser, zDate);



      cgi_printf("user:&nbsp;%z%h</a>", href("%z",zLink), zDispUser);
    }else{
      cgi_printf("user:&nbsp;%h", zDispUser);
    }

    /* Generate the "tags: TAGLIST" at the end of the comment, together
    ** with hyperlinks to the tag list.







|
>




>
>
|
>
>
>







649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
        cgi_printf("check-in:&nbsp;%z%S</a> ",href("%R/info/%!S",zUuid),zUuid);
      }else if( zType[0]=='e' && tagid ){
        cgi_printf("technote:&nbsp;");
        hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
      }else{
        cgi_printf("artifact:&nbsp;%z%S</a> ",href("%R/info/%!S",zUuid),zUuid);
      }
    }else if( zType[0]=='g' || zType[0]=='w' || zType[0]=='t'
              || zType[0]=='n' || zType[0]=='f'){
      cgi_printf("artifact:&nbsp;%z%S</a> ",href("%R/info/%!S",zUuid),zUuid);
    }

    if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){
      char *zLink;
      if( zType[0]!='f' || (tmFlags & TIMELINE_FORUMTXT)==0 ){
        zLink = mprintf("%R/timeline?u=%h&c=%t&y=a", zDispUser, zDate);
      }else{
        zLink = mprintf("%R/timeline?u=%h&c=%t&y=a&vfx", zDispUser, zDate);
      }
      cgi_printf("user:&nbsp;%z%h</a>", href("%z",zLink), zDispUser);
    }else{
      cgi_printf("user:&nbsp;%h", zDispUser);
    }

    /* Generate the "tags: TAGLIST" at the end of the comment, together
    ** with hyperlinks to the tag list.
763
764
765
766
767
768
769
















770
771
772
773
774
775
776
        fossil_free(zA);
      }
      db_reset(&fchngQuery);
      if( inUl ){
        @ </ul>
      }
    }
















  }
  if( suppressCnt ){
    @ <span class="timelineDisabled">... %d(suppressCnt) similar
    @ event%s(suppressCnt>1?"s":"") omitted.</span>
    suppressCnt = 0;
  }
  if( pendingEndTr ){







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







805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
        fossil_free(zA);
      }
      db_reset(&fchngQuery);
      if( inUl ){
        @ </ul>
      }
    }

    /* Show the complete text of forum messages */
    if( (tmFlags & (TIMELINE_FORUMTXT))!=0
     && zType[0]=='f' && g.perm.Hyperlink
     && (!content_is_private(rid) || g.perm.ModForum)
    ){
      Manifest *pPost = manifest_get(rid, CFTYPE_FORUM, 0);
      if( pPost ){
        const char *zClass = "forumTimeline";
        if( forum_rid_has_been_edited(rid) ){
          zClass = "forumTimeline forumObs";
        }
        forum_render(0, pPost->zMimetype, pPost->zWiki, zClass, 1);
        manifest_destroy(pPost);
      }
    }
  }
  if( suppressCnt ){
    @ <span class="timelineDisabled">... %d(suppressCnt) similar
    @ event%s(suppressCnt>1?"s":"") omitted.</span>
    suppressCnt = 0;
  }
  if( pendingEndTr ){
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
    *    br:  The branch to which the artifact belongs
    */
    aiMap = pGraph->aiRailMap;
    for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
      int k = 0;
      cgi_printf("{\"id\":%d,",     pRow->idx);
      cgi_printf("\"bg\":\"%s\",",  pRow->zBgClr);
      cgi_printf("\"r\":%d,",       aiMap[pRow->iRail]);
      if( pRow->bDescender ){
        cgi_printf("\"d\":%d,",       pRow->bDescender);
      }
      if( pRow->mergeOut>=0 ){
        cgi_printf("\"mo\":%d,",      aiMap[pRow->mergeOut]);
        if( pRow->mergeUpto==0 ) pRow->mergeUpto = pRow->idx;
        cgi_printf("\"mu\":%d,",      pRow->mergeUpto);







|







989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
    *    br:  The branch to which the artifact belongs
    */
    aiMap = pGraph->aiRailMap;
    for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
      int k = 0;
      cgi_printf("{\"id\":%d,",     pRow->idx);
      cgi_printf("\"bg\":\"%s\",",  pRow->zBgClr);
      cgi_printf("\"r\":%d,",       pRow->iRail>=0 ? aiMap[pRow->iRail] : -1);
      if( pRow->bDescender ){
        cgi_printf("\"d\":%d,",       pRow->bDescender);
      }
      if( pRow->mergeOut>=0 ){
        cgi_printf("\"mo\":%d,",      aiMap[pRow->mergeOut]);
        if( pRow->mergeUpto==0 ) pRow->mergeUpto = pRow->idx;
        cgi_printf("\"mu\":%d,",      pRow->mergeUpto);
1074
1075
1076
1077
1078
1079
1080
1081
1082

1083
1084
1085

1086
1087
1088
1089
1090
1091
1092
  const char *zDate;
  if( z==0 ) return -1.0;
  if( fossil_isdate(z) ){
    mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z);
    if( mtime>0.0 ) return mtime;
  }
  zDate = fossil_expand_datetime(z, 1);
  if( zDate!=0
   && (mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", zDate))>0.0

  ){
    if( pzDisplay ) *pzDisplay = fossil_strdup(zDate);
    return mtime;

  }
  rid = symbolic_name_to_rid(z, "*");
  if( rid ){
    mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
  }else{
    mtime = db_double(-1.0,
        "SELECT max(event.mtime) FROM event, tag, tagxref"







|
|
>
|
|
|
>







1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
  const char *zDate;
  if( z==0 ) return -1.0;
  if( fossil_isdate(z) ){
    mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z);
    if( mtime>0.0 ) return mtime;
  }
  zDate = fossil_expand_datetime(z, 1);
  if( zDate!=0 ){
    mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())",
                      fossil_roundup_date(zDate));
    if( mtime>0.0 ){
      if( pzDisplay ) *pzDisplay = fossil_strdup(zDate);
      return mtime;
    }
  }
  rid = symbolic_name_to_rid(z, "*");
  if( rid ){
    mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
  }else{
    mtime = db_double(-1.0,
        "SELECT max(event.mtime) FROM event, tag, tagxref"
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167


1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182











1183
1184
1185
1186
1187
1188
1189


1190
1191
1192
1193
1194
1195
1196
1197
1198
1199














1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215

1216
1217
1218
1219
1220
1221
1222
1223
/*
** Add the select/option box to the timeline submenu that is used to
** set the y= parameter that determines which elements to display
** on the timeline.
*/
static void timeline_y_submenu(int isDisabled){
  static int i = 0;
  static const char *az[14];
  if( i==0 ){
    az[0] = "all";
    az[1] = "Any Type";
    i = 2;
    if( g.perm.Read ){
      az[i++] = "ci";
      az[i++] = "Check-ins";
      az[i++] = "g";
      az[i++] = "Tags";
    }
    if( g.perm.RdWiki ){
      az[i++] = "e";
      az[i++] = "Tech Notes";
    }
    if( g.perm.RdTkt ){
      az[i++] = "t";
      az[i++] = "Tickets";


    }
    if( g.perm.RdWiki ){
      az[i++] = "w";
      az[i++] = "Wiki";
    }
    if( g.perm.RdForum ){
      az[i++] = "f";
      az[i++] = "Forum";
    }
    assert( i<=count(az) );
  }
  if( i>2 ){
    style_submenu_multichoice("y", i/2, az, isDisabled);
  }
}












/*
** Convert the current "ss" display preferences cookie into an
** appropriate TIMELINE_* flag
*/
int timeline_ss_cookie(void){
  int tmFlags;


  switch( cookie_value("ss","m")[0] ){
    case 'c':  tmFlags = TIMELINE_COMPACT;  break;
    case 'v':  tmFlags = TIMELINE_VERBOSE;  break;
    case 'j':  tmFlags = TIMELINE_COLUMNAR; break;
    case 'x':  tmFlags = TIMELINE_CLASSIC;  break;
    default:   tmFlags = TIMELINE_MODERN;   break;
  }
  return tmFlags;
}















/*
** Add the select/option box to the timeline submenu that is used to
** set the ss= parameter that determines the viewing mode.
**
** Return the TIMELINE_* value appropriate for the view-style.
*/
int timeline_ss_submenu(void){
  static const char *const azViewStyles[] = {
     "m", "Modern View",
     "j", "Columnar View",
     "c", "Compact View",
     "v", "Verbose View",
     "x", "Classic View",
  };
  cookie_link_parameter("ss","ss","m");
  style_submenu_multichoice("ss", sizeof(azViewStyles)/(2*sizeof(azViewStyles[0])),

                            azViewStyles, 0);
  return timeline_ss_cookie();
}

/*
** If the zChng string is not NULL, then it should be a comma-separated
** list of glob patterns for filenames.  Add an term to the WHERE clause
** for the SQL statement under construction that excludes any check-in that







|

















>
>















>
>
>
>
>
>
>
>
>
>
>







>
>
|









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







<
<
<
<
<
<
<
|
|
>
|







1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295







1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
/*
** Add the select/option box to the timeline submenu that is used to
** set the y= parameter that determines which elements to display
** on the timeline.
*/
static void timeline_y_submenu(int isDisabled){
  static int i = 0;
  static const char *az[16];
  if( i==0 ){
    az[0] = "all";
    az[1] = "Any Type";
    i = 2;
    if( g.perm.Read ){
      az[i++] = "ci";
      az[i++] = "Check-ins";
      az[i++] = "g";
      az[i++] = "Tags";
    }
    if( g.perm.RdWiki ){
      az[i++] = "e";
      az[i++] = "Tech Notes";
    }
    if( g.perm.RdTkt ){
      az[i++] = "t";
      az[i++] = "Tickets";
      az[i++] = "n";
      az[i++] = "New Tickets";
    }
    if( g.perm.RdWiki ){
      az[i++] = "w";
      az[i++] = "Wiki";
    }
    if( g.perm.RdForum ){
      az[i++] = "f";
      az[i++] = "Forum";
    }
    assert( i<=count(az) );
  }
  if( i>2 ){
    style_submenu_multichoice("y", i/2, az, isDisabled);
  }
}

/*
** Return the default value for the "ss" cookie or query parameter.
** The "ss" cookie determines the graph style.  See the
** timeline_view_styles[] global constant for a list of choices.
*/
const char *timeline_default_ss(void){
  static const char *zSs = 0;
  if( zSs==0 ) zSs = db_get("timeline-default-style","m");
  return zSs;
}

/*
** Convert the current "ss" display preferences cookie into an
** appropriate TIMELINE_* flag
*/
int timeline_ss_cookie(void){
  int tmFlags;
  const char *v = cookie_value("ss",0);
  if( v==0 ) v = timeline_default_ss();
  switch( v[0] ){
    case 'c':  tmFlags = TIMELINE_COMPACT;  break;
    case 'v':  tmFlags = TIMELINE_VERBOSE;  break;
    case 'j':  tmFlags = TIMELINE_COLUMNAR; break;
    case 'x':  tmFlags = TIMELINE_CLASSIC;  break;
    default:   tmFlags = TIMELINE_MODERN;   break;
  }
  return tmFlags;
}

/* Available timeline display styles, together with their y= query
** parameter names.
*/
const char *const timeline_view_styles[] = {
  "m", "Modern View",
  "j", "Columnar View",
  "c", "Compact View",
  "v", "Verbose View",
  "x", "Classic View",
};
#if INTERFACE
# define N_TIMELINE_VIEW_STYLE 5
#endif

/*
** Add the select/option box to the timeline submenu that is used to
** set the ss= parameter that determines the viewing mode.
**
** Return the TIMELINE_* value appropriate for the view-style.
*/
int timeline_ss_submenu(void){







  cookie_link_parameter("ss","ss",timeline_default_ss());
  style_submenu_multichoice("ss",
              N_TIMELINE_VIEW_STYLE,
              timeline_view_styles, 0);
  return timeline_ss_cookie();
}

/*
** If the zChng string is not NULL, then it should be a comma-separated
** list of glob patterns for filenames.  Add an term to the WHERE clause
** for the SQL statement under construction that excludes any check-in that
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526

1527

1528
1529
1530
1531
1532
1533
1534
**    t=TAG           Show only check-ins with the given TAG
**    r=TAG           Show check-ins related to TAG, equivalent to t=TAG&rel
**    rel             Show related check-ins as well as those matching t=TAG
**    mionly          Limit rel to show ancestors but not descendants
**    nowiki          Do not show wiki associated with branch or tag
**    ms=MATCHSTYLE   Set tag match style to EXACT, GLOB, LIKE, REGEXP
**    u=USER          Only show items associated with USER
**    y=TYPE          'ci', 'w', 't', 'e', 'f', or 'all'.
**    ss=VIEWSTYLE    c: "Compact"  v: "Verbose"   m: "Modern"  j: "Columnar"
**    advm            Use the "Advanced" or "Busy" menu design.
**    ng              No Graph.
**    ncp             Omit cherrypick merges
**    nd              Do not highlight the focus check-in

**    v               Show details of files changed

**    f=CHECKIN       Show family (immediate parents and children) of CHECKIN
**    from=CHECKIN    Path from...
**      to=CHECKIN      ... to this
**      shortest        ... show only the shortest path
**      rel             ... also show related checkins
**    uf=FILE_HASH    Show only check-ins that contain the given file version
**    chng=GLOBLIST   Show only check-ins that involve changes to a file whose







|





>

>







1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
**    t=TAG           Show only check-ins with the given TAG
**    r=TAG           Show check-ins related to TAG, equivalent to t=TAG&rel
**    rel             Show related check-ins as well as those matching t=TAG
**    mionly          Limit rel to show ancestors but not descendants
**    nowiki          Do not show wiki associated with branch or tag
**    ms=MATCHSTYLE   Set tag match style to EXACT, GLOB, LIKE, REGEXP
**    u=USER          Only show items associated with USER
**    y=TYPE          'ci', 'w', 't', 'n', 'e', 'f', or 'all'.
**    ss=VIEWSTYLE    c: "Compact"  v: "Verbose"   m: "Modern"  j: "Columnar"
**    advm            Use the "Advanced" or "Busy" menu design.
**    ng              No Graph.
**    ncp             Omit cherrypick merges
**    nd              Do not highlight the focus check-in
**    nsm             Omit the submenu
**    v               Show details of files changed
**    vfx             Show complete text of forum messages
**    f=CHECKIN       Show family (immediate parents and children) of CHECKIN
**    from=CHECKIN    Path from...
**      to=CHECKIN      ... to this
**      shortest        ... show only the shortest path
**      rel             ... also show related checkins
**    uf=FILE_HASH    Show only check-ins that contain the given file version
**    chng=GLOBLIST   Show only check-ins that involve changes to a file whose
1745
1746
1747
1748
1749
1750
1751



1752
1753
1754
1755
1756
1757
1758
  }
  if( PB("ncp") ){
    tmFlags &= ~TIMELINE_CHPICK;
  }
  if( PB("ng") || zSearch!=0 ){
    tmFlags &= ~(TIMELINE_GRAPH|TIMELINE_CHPICK);
  }



  if( PB("brbg") ){
    tmFlags |= TIMELINE_BRCOLOR;
  }
  if( PB("unhide") ){
    tmFlags |= TIMELINE_UNHIDE;
  }
  if( PB("ubg") ){







>
>
>







1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
  }
  if( PB("ncp") ){
    tmFlags &= ~TIMELINE_CHPICK;
  }
  if( PB("ng") || zSearch!=0 ){
    tmFlags &= ~(TIMELINE_GRAPH|TIMELINE_CHPICK);
  }
  if( PB("nsm") ){
    style_submenu_enable(0);
  }
  if( PB("brbg") ){
    tmFlags |= TIMELINE_BRCOLOR;
  }
  if( PB("unhide") ){
    tmFlags |= TIMELINE_UNHIDE;
  }
  if( PB("ubg") ){
1829
1830
1831
1832
1833
1834
1835



1836
1837
1838
1839
1840
1841
1842
  blob_zero(&sql);
  blob_zero(&desc);
  blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
  blob_append(&sql, timeline_query_for_www(), -1);
  if( PB("fc") || PB("v") || PB("detail") ){
    tmFlags |= TIMELINE_FCHANGES;
  }



  if( (tmFlags & TIMELINE_UNHIDE)==0 ){
    blob_append_sql(&sql,
      " AND NOT EXISTS(SELECT 1 FROM tagxref"
      " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)\n",
      TAG_HIDDEN
    );
  }







>
>
>







1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
  blob_zero(&sql);
  blob_zero(&desc);
  blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
  blob_append(&sql, timeline_query_for_www(), -1);
  if( PB("fc") || PB("v") || PB("detail") ){
    tmFlags |= TIMELINE_FCHANGES;
  }
  if( PB("vfx") ){
    tmFlags |= TIMELINE_FORUMTXT;
  }
  if( (tmFlags & TIMELINE_UNHIDE)==0 ){
    blob_append_sql(&sql,
      " AND NOT EXISTS(SELECT 1 FROM tagxref"
      " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)\n",
      TAG_HIDDEN
    );
  }
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
    db_multi_exec(
      "CREATE TABLE IF NOT EXISTS temp.pathnode(x INTEGER PRIMARY KEY);"
    );
    if( p ){
      blob_init(&ins, 0, 0);
      blob_append_sql(&ins, "INSERT INTO pathnode(x) VALUES(%d)", p->rid);
      p = p->u.pTo;
      nNodeOnPath = 1;
      while( p ){
        blob_append_sql(&ins, ",(%d)", p->rid);
        p = p->u.pTo;
        nNodeOnPath++;
      }
    }
    path_reset();
    db_multi_exec("%s", blob_str(&ins)/*safe-for-%s*/);
    blob_reset(&ins);
    if( related ){
      db_multi_exec(







<



<







1955
1956
1957
1958
1959
1960
1961

1962
1963
1964

1965
1966
1967
1968
1969
1970
1971
    db_multi_exec(
      "CREATE TABLE IF NOT EXISTS temp.pathnode(x INTEGER PRIMARY KEY);"
    );
    if( p ){
      blob_init(&ins, 0, 0);
      blob_append_sql(&ins, "INSERT INTO pathnode(x) VALUES(%d)", p->rid);
      p = p->u.pTo;

      while( p ){
        blob_append_sql(&ins, ",(%d)", p->rid);
        p = p->u.pTo;

      }
    }
    path_reset();
    db_multi_exec("%s", blob_str(&ins)/*safe-for-%s*/);
    blob_reset(&ins);
    if( related ){
      db_multi_exec(
1901
1902
1903
1904
1905
1906
1907
1908








1909
1910
1911
1912
1913
1914

1915
1916
1917
1918
1919
1920
1921
            "  SELECT childid FROM cherrypick WHERE parentid IN pathnode;"
          );
        }
      }
      db_multi_exec("INSERT OR IGNORE INTO pathnode SELECT x FROM related");
    }
    blob_append_sql(&sql, " AND event.objid IN pathnode");
    addFileGlobExclusion(zChng, &sql);








    tmFlags |= TIMELINE_DISJOINT;
    tmFlags &= ~TIMELINE_CHPICK;
    db_multi_exec("%s", blob_sql_text(&sql));
    if( advancedMenu ){
      style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0);
    }

    blob_appendf(&desc, "%d check-ins going from ", nNodeOnPath);
    blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom);
    blob_append(&desc, " to ", -1);
    blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
    if( related ){
      int nRelated = db_int(0, "SELECT count(*) FROM timeline") - nNodeOnPath;
      if( nRelated>0 ){







|
>
>
>
>
>
>
>
>






>







1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
            "  SELECT childid FROM cherrypick WHERE parentid IN pathnode;"
          );
        }
      }
      db_multi_exec("INSERT OR IGNORE INTO pathnode SELECT x FROM related");
    }
    blob_append_sql(&sql, " AND event.objid IN pathnode");
    if( zChng && zChng[0] ){
      db_multi_exec(
        "DELETE FROM pathnode "
        " WHERE NOT EXISTS(SELECT 1 FROM mlink, filename"
                          " WHERE mlink.mid=x"
                          "   AND mlink.fnid=filename.fnid AND %s)",
        glob_expr("filename.name", zChng)
      );
    }
    tmFlags |= TIMELINE_DISJOINT;
    tmFlags &= ~TIMELINE_CHPICK;
    db_multi_exec("%s", blob_sql_text(&sql));
    if( advancedMenu ){
      style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0);
    }
    nNodeOnPath = db_int(0, "SELECT count(*) FROM temp.pathnode");
    blob_appendf(&desc, "%d check-ins going from ", nNodeOnPath);
    blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom);
    blob_append(&desc, " to ", -1);
    blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
    if( related ){
      int nRelated = db_int(0, "SELECT count(*) FROM timeline") - nNodeOnPath;
      if( nRelated>0 ){
2138
2139
2140
2141
2142
2143
2144

2145
2146
2147
2148
2149
2150
2151
            TAG_HIDDEN
          );
        }
      }
    }
    if( (zType[0]=='w' && !g.perm.RdWiki)
     || (zType[0]=='t' && !g.perm.RdTkt)

     || (zType[0]=='e' && !g.perm.RdWiki)
     || (zType[0]=='c' && !g.perm.Read)
     || (zType[0]=='g' && !g.perm.Read)
     || (zType[0]=='f' && !g.perm.RdForum)
    ){
      zType = "all";
    }







>







2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
            TAG_HIDDEN
          );
        }
      }
    }
    if( (zType[0]=='w' && !g.perm.RdWiki)
     || (zType[0]=='t' && !g.perm.RdTkt)
     || (zType[0]=='n' && !g.perm.RdTkt)
     || (zType[0]=='e' && !g.perm.RdWiki)
     || (zType[0]=='c' && !g.perm.Read)
     || (zType[0]=='g' && !g.perm.Read)
     || (zType[0]=='f' && !g.perm.RdForum)
    ){
      zType = "all";
    }
2168
2169
2170
2171
2172
2173
2174




2175

2176
2177
2178
2179
2180
2181


2182
2183
2184
2185
2186
2187
2188
        if( g.perm.RdForum ){
          blob_append_sql(&cond, "%c'f'", cSep);
          cSep = ',';
        }
        blob_append_sql(&cond, ")");
      }
    }else{ /* zType!="all" */




      blob_append_sql(&cond, " AND event.type=%Q", zType);

      if( zType[0]=='c' ){
        zEType = "check-in";
      }else if( zType[0]=='w' ){
        zEType = "wiki";
      }else if( zType[0]=='t' ){
        zEType = "ticket change";


      }else if( zType[0]=='e' ){
        zEType = "technical note";
      }else if( zType[0]=='g' ){
        zEType = "tag";
      }else if( zType[0]=='f' ){
        zEType = "forum post";
      }







>
>
>
>
|
>






>
>







2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
        if( g.perm.RdForum ){
          blob_append_sql(&cond, "%c'f'", cSep);
          cSep = ',';
        }
        blob_append_sql(&cond, ")");
      }
    }else{ /* zType!="all" */
      if( zType[0]=='n' ){
        blob_append_sql(&cond,
            " AND event.type='t' AND event.comment GLOB 'New ticket*'");
      }else{
        blob_append_sql(&cond, " AND event.type=%Q", zType);
      }
      if( zType[0]=='c' ){
        zEType = "check-in";
      }else if( zType[0]=='w' ){
        zEType = "wiki";
      }else if( zType[0]=='t' ){
        zEType = "ticket change";
      }else if( zType[0]=='n' ){
        zEType = "new tickets";
      }else if( zType[0]=='e' ){
        zEType = "technical note";
      }else if( zType[0]=='g' ){
        zEType = "tag";
      }else if( zType[0]=='f' ){
        zEType = "forum post";
      }
Changes to src/tkt.c.
192
193
194
195
196
197
198

199
200
201
202
203
204
205
** Return the new rowid of the TICKET table entry.
*/
static int ticket_insert(const Manifest *p, int rid, int tktid){
  Blob sql1, sql2, sql3;
  Stmt q;
  int i, j;
  char *aUsed;


  if( tktid==0 ){
    db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
                  "VALUES(%Q, 0)", p->zTicketUuid);
    tktid = db_last_insert_rowid();
  }
  blob_zero(&sql1);







>







192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
** Return the new rowid of the TICKET table entry.
*/
static int ticket_insert(const Manifest *p, int rid, int tktid){
  Blob sql1, sql2, sql3;
  Stmt q;
  int i, j;
  char *aUsed;
  const char *zMimetype = 0;

  if( tktid==0 ){
    db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
                  "VALUES(%Q, 0)", p->zTicketUuid);
    tktid = db_last_insert_rowid();
  }
  blob_zero(&sql1);
231
232
233
234
235
236
237




238






239
240
241
242
243
244
245
246
      const char *zUsedByName = zName;
      if( zUsedByName[0]=='+' ){
        zUsedByName++;
      }
      blob_append_sql(&sql2, ",\"%w\"", zUsedByName);
      blob_append_sql(&sql3, ",%Q", p->aField[i].zValue);
    }




    if( rid>0 ){






      wiki_extract_links(p->aField[i].zValue, rid, 1, p->rDate, i==0, 0);
    }
  }
  blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid);
  db_prepare(&q, "%s", blob_sql_text(&sql1));
  db_bind_double(&q, ":mtime", p->rDate);
  db_step(&q);
  db_finalize(&q);







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







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
      const char *zUsedByName = zName;
      if( zUsedByName[0]=='+' ){
        zUsedByName++;
      }
      blob_append_sql(&sql2, ",\"%w\"", zUsedByName);
      blob_append_sql(&sql3, ",%Q", p->aField[i].zValue);
    }
    if( strcmp(zBaseName,"mimetype")==0 ){
      zMimetype = p->aField[i].zValue;
    }
  }
  if( rid>0 ){
    for(i=0; i<p->nField; i++){
      const char *zName = p->aField[i].zName;
      const char *zBaseName = zName[0]=='+' ? zName+1 : zName;
      j = fieldId(zBaseName);
      if( j<0 ) continue;
      backlink_extract(p->aField[i].zValue, zMimetype, rid, BKLNK_TICKET,
                       p->rDate, i==0);
    }
  }
  blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid);
  db_prepare(&q, "%s", blob_sql_text(&sql1));
  db_bind_double(&q, ":mtime", p->rDate);
  db_step(&q);
  db_finalize(&q);
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
  return Th_Eval(g.interp, 0, zConfig, -1);
}

/*
** Recreate the TICKET and TICKETCHNG tables.
*/
void ticket_create_table(int separateConnection){
  const char *zSql;

  db_multi_exec(
    "DROP TABLE IF EXISTS ticket;"
    "DROP TABLE IF EXISTS ticketchng;"
  );
  zSql = ticket_table_schema();
  if( separateConnection ){
    if( db_transaction_nesting_depth() ) db_end_transaction(0);
    db_init_database(g.zRepositoryName, zSql, 0);
  }else{
    db_multi_exec("%s", zSql/*safe-for-%s*/);
  }

}

/*
** Repopulate the TICKET and TICKETCHNG tables from scratch using all
** available ticket artifacts.
*/
void ticket_rebuild(void){







|












>







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
  return Th_Eval(g.interp, 0, zConfig, -1);
}

/*
** Recreate the TICKET and TICKETCHNG tables.
*/
void ticket_create_table(int separateConnection){
  char *zSql;

  db_multi_exec(
    "DROP TABLE IF EXISTS ticket;"
    "DROP TABLE IF EXISTS ticketchng;"
  );
  zSql = ticket_table_schema();
  if( separateConnection ){
    if( db_transaction_nesting_depth() ) db_end_transaction(0);
    db_init_database(g.zRepositoryName, zSql, 0);
  }else{
    db_multi_exec("%s", zSql/*safe-for-%s*/);
  }
  fossil_free(zSql);
}

/*
** Repopulate the TICKET and TICKETCHNG tables from scratch using all
** available ticket artifacts.
*/
void ticket_rebuild(void){
442
443
444
445
446
447
448
449
450
451



452
453
454
455
456

457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480













481
482
483
484
485
486
487
    @ mUsed = %d(aField[i].mUsed);
  }
  @ </ul></div>
}

/*
** WEBPAGE: tktview
** URL:  tktview?name=UUID
**
** View a ticket identified by the name= query parameter.



*/
void tktview_page(void){
  const char *zScript;
  char *zFullName;
  const char *zUuid = PD("name","");


  login_check_credentials();
  if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
  if( g.anon.WrTkt || g.anon.ApndTkt ){
    style_submenu_element("Edit", "%s/tktedit?name=%T", g.zTop, PD("name",""));
  }
  if( g.perm.Hyperlink ){
    style_submenu_element("History", "%s/tkthistory/%T", g.zTop, zUuid);
    style_submenu_element("Timeline", "%s/tkttimeline/%T", g.zTop, zUuid);
    style_submenu_element("Check-ins", "%s/tkttimeline/%T?y=ci", g.zTop, zUuid);
  }
  if( g.anon.NewTkt ){
    style_submenu_element("New Ticket", "%s/tktnew", g.zTop);
  }
  if( g.anon.ApndTkt && g.anon.Attach ){
    style_submenu_element("Attach", "%s/attachadd?tkt=%T&from=%s/tktview/%t",
        g.zTop, zUuid, g.zTop, zUuid);
  }
  if( P("plaintext") ){
    style_submenu_element("Formatted", "%R/tktview/%s", zUuid);
  }else{
    style_submenu_element("Plaintext", "%R/tktview/%s?plaintext", zUuid);
  }
  style_header("View Ticket");













  if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
  ticket_init();
  initializeVariablesFromCGI();
  getAllTicketFields();
  initializeVariablesFromDb();
  zScript = ticket_viewpage_code();
  if( P("showfields")!=0 ) showAllFields();







|


>
>
>





>








<















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







454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480

481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
    @ mUsed = %d(aField[i].mUsed);
  }
  @ </ul></div>
}

/*
** WEBPAGE: tktview
** URL:  tktview?name=HASH
**
** View a ticket identified by the name= query parameter.
** Other query parameters:
**
**      tl               Show a timeline of the ticket above the status
*/
void tktview_page(void){
  const char *zScript;
  char *zFullName;
  const char *zUuid = PD("name","");
  int showTimeline = P("tl")!=0;

  login_check_credentials();
  if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
  if( g.anon.WrTkt || g.anon.ApndTkt ){
    style_submenu_element("Edit", "%s/tktedit?name=%T", g.zTop, PD("name",""));
  }
  if( g.perm.Hyperlink ){
    style_submenu_element("History", "%s/tkthistory/%T", g.zTop, zUuid);

    style_submenu_element("Check-ins", "%s/tkttimeline/%T?y=ci", g.zTop, zUuid);
  }
  if( g.anon.NewTkt ){
    style_submenu_element("New Ticket", "%s/tktnew", g.zTop);
  }
  if( g.anon.ApndTkt && g.anon.Attach ){
    style_submenu_element("Attach", "%s/attachadd?tkt=%T&from=%s/tktview/%t",
        g.zTop, zUuid, g.zTop, zUuid);
  }
  if( P("plaintext") ){
    style_submenu_element("Formatted", "%R/tktview/%s", zUuid);
  }else{
    style_submenu_element("Plaintext", "%R/tktview/%s?plaintext", zUuid);
  }
  style_header("View Ticket");
  if( showTimeline ){
    int tagid = db_int(0,"SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
                       zUuid);
    if( tagid ){
      tkt_draw_timeline(tagid, "a");
      @ <hr>
    }else{
      showTimeline = 0;
    }
  }
  if( !showTimeline && g.perm.Hyperlink ){
    style_submenu_element("Timeline", "%s/info/%T", g.zTop, zUuid);
  }
  if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
  ticket_init();
  initializeVariablesFromCGI();
  getAllTicketFields();
  initializeVariablesFromDb();
  zScript = ticket_viewpage_code();
  if( P("showfields")!=0 ) showAllFields();
822
823
824
825
826
827
828
829
830


















































831
832
833
834




835
836
837
838
839
840
841
842
843
844
845
846
847
848
                       "table containing all required fields");
      }
    }
    sqlite3_close(db);
  }
  return zErr;
}

/*


















































** WEBPAGE: tkttimeline
** URL: /tkttimeline?name=TICKETUUID&y=TYPE
**
** Show the change history for a single ticket in timeline format.




*/
void tkttimeline_page(void){
  Stmt q;
  char *zTitle;
  char *zSQL;
  const char *zUuid;
  char *zFullUuid;
  int tagid;
  char zGlobPattern[50];
  const char *zType;

  login_check_credentials();
  if( !g.perm.Hyperlink || !g.perm.RdTkt ){
    login_needed(g.anon.Hyperlink && g.anon.RdTkt);









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

|


>
>
>
>


<

<

<







850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
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
                       "table containing all required fields");
      }
    }
    sqlite3_close(db);
  }
  return zErr;
}

/*
** Draw a timeline for a ticket with tag.tagid given by the tagid
** parameter.
**
** If zType[0]=='c' then only show check-ins associated with the
** ticket.  For any other value of zType, show all events associated
** with the ticket.
*/
void tkt_draw_timeline(int tagid, const char *zType){
  Stmt q;
  char *zFullUuid;
  char *zSQL;
  zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
                         tagid);
  if( zType[0]=='c' ){
    zSQL = mprintf(
         "%s AND event.objid IN "
         " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
                                         "AND srctype=0 "
                                         "AND '%s' GLOB (target||'*')) "
         "ORDER BY mtime DESC",
         timeline_query_for_www(), zFullUuid, zFullUuid
    );
  }else{
    zSQL = mprintf(
         "%s AND event.objid IN "
         "  (SELECT rid FROM tagxref WHERE tagid=%d"
         "   UNION"
         "   SELECT CASE srctype WHEN 2 THEN"
                 " (SELECT rid FROM tagxref WHERE tagid=backlink.srcid"
                 " ORDER BY mtime DESC LIMIT 1)"
                 " ELSE srcid END"
         "     FROM backlink"
                  " WHERE target GLOB '%.4s*'"
                  "   AND '%s' GLOB (target||'*')"
         "   UNION SELECT attachid FROM attachment"
                  " WHERE target=%Q) "
         "ORDER BY mtime DESC",
         timeline_query_for_www(), tagid, zFullUuid, zFullUuid, zFullUuid
    );
  }
  db_prepare(&q, "%z", zSQL/*safe-for-%s*/);
  www_print_timeline(&q,
    TIMELINE_ARTID | TIMELINE_DISJOINT | TIMELINE_GRAPH | TIMELINE_NOTKT |
    TIMELINE_REFS,
    0, 0, 0, 0, 0, 0);
  db_finalize(&q);
  fossil_free(zFullUuid);
}

/*
** WEBPAGE: tkttimeline
** URL: /tkttimeline/TICKETUUID
**
** Show the change history for a single ticket in timeline format.
** 
** Query parameters:
**
**     y=ci          Show only check-ins associated with the ticket
*/
void tkttimeline_page(void){

  char *zTitle;

  const char *zUuid;

  int tagid;
  char zGlobPattern[50];
  const char *zType;

  login_check_credentials();
  if( !g.perm.Hyperlink || !g.perm.RdTkt ){
    login_needed(g.anon.Hyperlink && g.anon.RdTkt);
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
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
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
  canonical16(zGlobPattern, strlen(zGlobPattern));
  tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
  if( tagid==0 ){
    @ No such ticket: %h(zUuid)
    style_footer();
    return;
  }
  zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
                         tagid);
  if( zType[0]=='c' ){
    zSQL = mprintf(
         "%s AND event.objid IN "
         "   (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
                                         "AND '%s' GLOB (target||'*')) "
         "ORDER BY mtime DESC",
         timeline_query_for_www(), zFullUuid, zFullUuid
    );
  }else{
    zSQL = mprintf(
         "%s AND event.objid IN "
         "  (SELECT rid FROM tagxref WHERE tagid=%d"
         "   UNION SELECT srcid FROM backlink"
                  " WHERE target GLOB '%.4s*'"
                  "   AND '%s' GLOB (target||'*')"
         "   UNION SELECT attachid FROM attachment"
                  " WHERE target=%Q) "
         "ORDER BY mtime DESC",
         timeline_query_for_www(), tagid, zFullUuid, zFullUuid, zFullUuid
    );
  }
  db_prepare(&q, "%z", zSQL/*safe-for-%s*/);
  www_print_timeline(&q, TIMELINE_ARTID|TIMELINE_DISJOINT|TIMELINE_GRAPH,
                     0, 0, 0, 0, 0, 0);
  db_finalize(&q);
  style_footer();
}

/*
** WEBPAGE: tkthistory
** URL: /tkthistory?name=TICKETUUID
**
** Show the complete change history for a single ticket







*/
void tkthistory_page(void){
  Stmt q;
  char *zTitle;
  const char *zUuid;
  int tagid;
  int nChng = 0;

  login_check_credentials();
  if( !g.perm.Hyperlink || !g.perm.RdTkt ){
    login_needed(g.anon.Hyperlink && g.anon.RdTkt);
    return;
  }
  zUuid = PD("name","");
  zTitle = mprintf("History Of Ticket %h", zUuid);
  style_submenu_element("Status", "%s/info/%s", g.zTop, zUuid);
  style_submenu_element("Check-ins", "%s/tkttimeline?name=%s&y=ci",
    g.zTop, zUuid);
  style_submenu_element("Timeline", "%s/tkttimeline?name=%s", g.zTop, zUuid);
  if( P("plaintext")!=0 ){
    style_submenu_element("Formatted", "%R/tkthistory/%s", zUuid);
  }else{
    style_submenu_element("Plaintext", "%R/tkthistory/%s?plaintext", zUuid);
  }
  style_header("%z", zTitle);

  tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
  if( tagid==0 ){
    @ No such ticket: %h(zUuid)
    style_footer();
    return;
  }





  db_prepare(&q,
    "SELECT datetime(mtime,toLocal()), objid, uuid, NULL, NULL, NULL"
    "  FROM event, blob"
    " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
    "   AND blob.rid=event.objid"
    " UNION "
    "SELECT datetime(mtime,toLocal()), attachid, uuid, src, filename, user"
    "  FROM attachment, blob"
    " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
    "   AND blob.rid=attachid"
    " ORDER BY 1",
    tagid, tagid
  );
  while( db_step(&q)==SQLITE_ROW ){
    Manifest *pTicket;
    const char *zDate = db_column_text(&q, 0);
    int rid = db_column_int(&q, 1);
    const char *zChngUuid = db_column_text(&q, 2);
    const char *zFile = db_column_text(&q, 4);
    if( nChng==0 ){
      @ <ol>
    }
    nChng++;
    if( zFile!=0 ){
      const char *zSrc = db_column_text(&q, 3);
      const char *zUser = db_column_text(&q, 5);
      if( zSrc==0 || zSrc[0]==0 ){
        @
        @ <li><p>Delete attachment "%h(zFile)"
      }else{







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







|
>
>
>
>
>
>
>



















|
|
|
|









>
>
>
>
>













|








<







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
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029

1030
1031
1032
1033
1034
1035
1036
  canonical16(zGlobPattern, strlen(zGlobPattern));
  tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
  if( tagid==0 ){
    @ No such ticket: %h(zUuid)
    style_footer();
    return;
  }

  tkt_draw_timeline(tagid, zType);

























  style_footer();
}

/*
** WEBPAGE: tkthistory
** URL: /tkthistory?name=TICKETUUID
**
** Show the complete change history for a single ticket.  Or (to put it
** another way) show a list of artifacts associated with a single ticket.
**
** By default, the artifacts are decoded and formatted.  Text fields
** are formatted as text/plain, since in the general case Fossil does
** not have knowledge of the encoding.  If the "raw" query parameter
** is present, then the* undecoded and unformatted text of each artifact
** is displayed.
*/
void tkthistory_page(void){
  Stmt q;
  char *zTitle;
  const char *zUuid;
  int tagid;
  int nChng = 0;

  login_check_credentials();
  if( !g.perm.Hyperlink || !g.perm.RdTkt ){
    login_needed(g.anon.Hyperlink && g.anon.RdTkt);
    return;
  }
  zUuid = PD("name","");
  zTitle = mprintf("History Of Ticket %h", zUuid);
  style_submenu_element("Status", "%s/info/%s", g.zTop, zUuid);
  style_submenu_element("Check-ins", "%s/tkttimeline?name=%s&y=ci",
    g.zTop, zUuid);
  style_submenu_element("Timeline", "%s/tkttimeline?name=%s", g.zTop, zUuid);
  if( P("raw")!=0 ){
    style_submenu_element("Decoded", "%R/tkthistory/%s", zUuid);
  }else if( g.perm.Admin ){
    style_submenu_element("Raw", "%R/tkthistory/%s?raw", zUuid);
  }
  style_header("%z", zTitle);

  tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
  if( tagid==0 ){
    @ No such ticket: %h(zUuid)
    style_footer();
    return;
  }
  if( P("raw")!=0 ){
    @ <h2>Raw Artifacts Associated With Ticket %h(zUuid)</h2>
  }else{
    @ <h2>Artifacts Associated With Ticket %h(zUuid)</h2>
  }
  db_prepare(&q,
    "SELECT datetime(mtime,toLocal()), objid, uuid, NULL, NULL, NULL"
    "  FROM event, blob"
    " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
    "   AND blob.rid=event.objid"
    " UNION "
    "SELECT datetime(mtime,toLocal()), attachid, uuid, src, filename, user"
    "  FROM attachment, blob"
    " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
    "   AND blob.rid=attachid"
    " ORDER BY 1",
    tagid, tagid
  );
  for(nChng=0; db_step(&q)==SQLITE_ROW; nChng++){
    Manifest *pTicket;
    const char *zDate = db_column_text(&q, 0);
    int rid = db_column_int(&q, 1);
    const char *zChngUuid = db_column_text(&q, 2);
    const char *zFile = db_column_text(&q, 4);
    if( nChng==0 ){
      @ <ol>
    }

    if( zFile!=0 ){
      const char *zSrc = db_column_text(&q, 3);
      const char *zUser = db_column_text(&q, 5);
      if( zSrc==0 || zSrc[0]==0 ){
        @
        @ <li><p>Delete attachment "%h(zFile)"
      }else{
984
985
986
987
988
989
990








991

992
993
994
995
996
997
998
        @
        @ <li><p>Ticket change
        @ [%z(href("%R/artifact/%!S",zChngUuid))%S(zChngUuid)</a>]
        @ (rid %d(rid)) by
        hyperlink_to_user(pTicket->zUser,zDate," on");
        hyperlink_to_date(zDate, ":");
        @ </p>








        ticket_output_change_artifact(pTicket, "a");

      }
      manifest_destroy(pTicket);
    }
  }
  db_finalize(&q);
  if( nChng ){
    @ </ol>







>
>
>
>
>
>
>
>
|
>







1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
        @
        @ <li><p>Ticket change
        @ [%z(href("%R/artifact/%!S",zChngUuid))%S(zChngUuid)</a>]
        @ (rid %d(rid)) by
        hyperlink_to_user(pTicket->zUser,zDate," on");
        hyperlink_to_date(zDate, ":");
        @ </p>
        if( P("raw")!=0 ){
          Blob c;
          content_get(rid, &c);
          @ <blockquote><pre>
          @ %h(blob_str(&c))
          @ </pre></blockquote>
          blob_reset(&c);
        }else{
          ticket_output_change_artifact(pTicket, "a", nChng);
        }
      }
      manifest_destroy(pTicket);
    }
  }
  db_finalize(&q);
  if( nChng ){
    @ </ol>
1012
1013
1014
1015
1016
1017
1018
1019




1020
1021
1022
1023
1024
1025
1026
1027
1028
1029

1030
1031
1032
1033

1034
1035
1036









1037
1038

1039

1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  return 0;
}

/*
** The pTkt object is a ticket change artifact.  Output a detailed
** description of this object.
*/
void ticket_output_change_artifact(Manifest *pTkt, const char *zListType){




  int i;
  int wikiFlags = WIKI_NOBADLINKS;
  const char *zBlock = "<blockquote>";
  const char *zEnd = "</blockquote>";
  if( P("plaintext")!=0 ){
    wikiFlags |= WIKI_LINKSONLY;
    zBlock = "<blockquote><pre class='verbatim'>";
    zEnd = "</pre></blockquote>";
  }
  if( zListType==0 ) zListType = "1";

  @ <ol type="%s(zListType)">
  for(i=0; i<pTkt->nField; i++){
    Blob val;
    const char *z;

    z = pTkt->aField[i].zName;
    blob_set(&val, pTkt->aField[i].zValue);
    if( z[0]=='+' ){









      @ <li>Appended to %h(&z[1]):%s(zBlock)
      wiki_convert(&val, 0, wikiFlags);

      @ %s(zEnd)</li>

    }else if( blob_size(&val)>50 || contains_newline(&val) ){
      @ <li>Change %h(z) to:%s(zBlock)
      wiki_convert(&val, 0, wikiFlags);
      @ %s(zEnd)</li>
    }else{
      @ <li>Change %h(z) to "%h(blob_str(&val))"</li>
    }
    blob_reset(&val);
  }
  @ </ol>
}

/*







|
>
>
>
>

<
<
<
<
<
<
<
<

>



|
>


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

|







1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097








1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117

1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
  return 0;
}

/*
** The pTkt object is a ticket change artifact.  Output a detailed
** description of this object.
*/
void ticket_output_change_artifact(
  Manifest *pTkt,           /* Parsed artifact for the ticket change */
  const char *zListType,    /* Which type of list */
  int n                     /* Which ticket change is this */
){
  int i;








  if( zListType==0 ) zListType = "1";
  getAllTicketFields();
  @ <ol type="%s(zListType)">
  for(i=0; i<pTkt->nField; i++){
    Blob val;
    const char *z, *zX;
    int id;
    z = pTkt->aField[i].zName;
    blob_set(&val, pTkt->aField[i].zValue);
    zX = z[0]=='+' ? z+1 : z;
    id = fieldId(zX);
    @ <li>\
    if( id<0 ){
      @ Untracked field %h(zX):
    }else if( aField[id].mUsed==USEDBY_TICKETCHNG ){
      @ %h(zX):
    }else if( n==0 ){
      @ %h(zX) initialized to:
    }else if( z[0]=='+' && (aField[id].mUsed&USEDBY_TICKET)!=0 ){
      @ Appended to %h(zX):

    }else{
      @ %h(zX) changed to:
    }
    if( blob_size(&val)>50 || contains_newline(&val) ){
      @ <blockquote><pre class='verbatim'>
      @ %h(blob_str(&val))
      @ </pre></blockquote></li>
    }else{
      @ "%h(blob_str(&val))"</li>
    }
    blob_reset(&val);
  }
  @ </ol>
}

/*
Changes to src/tktsetup.c.
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
109
110
@   mimetype TEXT,
@   icomment TEXT
@ );
@ CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime);
;

/*
** Return the ticket table definition

*/
const char *ticket_table_schema(void){
  return db_get("ticket-table", zDefaultTicketTable);
}

/*
** Common implementation for the ticket setup editor pages.
*/
static void tktsetup_generic(







|
>

|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
@   mimetype TEXT,
@   icomment TEXT
@ );
@ CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime);
;

/*
** Return the ticket table definition in heap-allocated
** memory owned by the caller.
*/
char *ticket_table_schema(void){
  return db_get("ticket-table", zDefaultTicketTable);
}

/*
** Common implementation for the ticket setup editor pages.
*/
static void tktsetup_generic(
907
908
909
910
911
912
913
914

915
916
917
918
919
920

921
922
923
924
925
926

927
928
929
930
931
932
933
934
935
936
937
  @ <form action="%s(g.zTop)/tktsetup_timeline" method="post"><div>
  login_insert_csrf_secret();

  @ <hr />
  entry_attribute("Ticket Title", 40, "ticket-title-expr", "t",
                  "title", 0);
  @ <p>An SQL expression in a query against the TICKET table that will
  @ return the title of the ticket for display purposes.</p>


  @ <hr />
  entry_attribute("Ticket Status", 40, "ticket-status-column", "s",
                  "status", 0);
  @ <p>The name of the column in the TICKET table that contains the ticket
  @ status in human-readable form.  Case sensitive.</p>


  @ <hr />
  entry_attribute("Ticket Closed", 40, "ticket-closed-expr", "c",
                  "status='Closed'", 0);
  @ <p>An SQL expression that evaluates to true in a TICKET table query if
  @ the ticket is closed.</p>


  @ <hr />
  @ <p>
  @ <input type="submit"  name="submit" value="Apply Changes" />
  @ <input type="submit" name="setup" value="Cancel" />
  @ </p>
  @ </div></form>
  db_end_transaction(0);
  style_footer();

}







|
>





|
>





|
>











908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
  @ <form action="%s(g.zTop)/tktsetup_timeline" method="post"><div>
  login_insert_csrf_secret();

  @ <hr />
  entry_attribute("Ticket Title", 40, "ticket-title-expr", "t",
                  "title", 0);
  @ <p>An SQL expression in a query against the TICKET table that will
  @ return the title of the ticket for display purposes.
  @ (Property: ticket-title-expr)</p>

  @ <hr />
  entry_attribute("Ticket Status", 40, "ticket-status-column", "s",
                  "status", 0);
  @ <p>The name of the column in the TICKET table that contains the ticket
  @ status in human-readable form.  Case sensitive.
  @ (Property: ticket-status-column)</p>

  @ <hr />
  entry_attribute("Ticket Closed", 40, "ticket-closed-expr", "c",
                  "status='Closed'", 0);
  @ <p>An SQL expression that evaluates to true in a TICKET table query if
  @ the ticket is closed.
  @ (Property: ticket-closed-expr)</p>

  @ <hr />
  @ <p>
  @ <input type="submit"  name="submit" value="Apply Changes" />
  @ <input type="submit" name="setup" value="Cancel" />
  @ </p>
  @ </div></form>
  db_end_transaction(0);
  style_footer();

}
Changes to src/undo.c.
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  static const char zSql[] =
    @ DROP TABLE IF EXISTS undo;
    @ DROP TABLE IF EXISTS undo_vfile;
    @ DROP TABLE IF EXISTS undo_vmerge;
    @ DROP TABLE IF EXISTS undo_stash;
    @ DROP TABLE IF EXISTS undo_stashfile;
    ;
  db_multi_exec(zSql /*works-like:""*/);
  db_lset_int("undo_available", 0);
  db_lset_int("undo_checkout", 0);
}

/*
** The following variable stores the original command-line of the
** command that is a candidate to be undone.







|







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  static const char zSql[] =
    @ DROP TABLE IF EXISTS undo;
    @ DROP TABLE IF EXISTS undo_vfile;
    @ DROP TABLE IF EXISTS undo_vmerge;
    @ DROP TABLE IF EXISTS undo_stash;
    @ DROP TABLE IF EXISTS undo_stashfile;
    ;
  db_exec_sql(zSql);
  db_lset_int("undo_available", 0);
  db_lset_int("undo_checkout", 0);
}

/*
** The following variable stores the original command-line of the
** command that is a candidate to be undone.
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
    @   content BLOB                      -- Saved content
    @ );
    @ CREATE TABLE localdb.undo_vfile AS SELECT * FROM vfile;
    @ CREATE TABLE localdb.undo_vmerge AS SELECT * FROM vmerge;
  ;
  if( undoDisable ) return;
  undo_reset();
  db_multi_exec(zSql/*works-like:""*/);
  cid = db_lget_int("checkout", 0);
  db_lset_int("undo_checkout", cid);
  db_lset_int("undo_available", 1);
  db_lset("undo_cmdline", undoCmd);
  undoActive = 1;
}








|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
    @   content BLOB                      -- Saved content
    @ );
    @ CREATE TABLE localdb.undo_vfile AS SELECT * FROM vfile;
    @ CREATE TABLE localdb.undo_vmerge AS SELECT * FROM vmerge;
  ;
  if( undoDisable ) return;
  undo_reset();
  db_exec_sql(zSql);
  cid = db_lget_int("checkout", 0);
  db_lset_int("undo_checkout", cid);
  db_lset_int("undo_available", 1);
  db_lset("undo_cmdline", undoCmd);
  undoActive = 1;
}

421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
445
446






447
448




449
450
451
452
453
454
455
/*
** COMMAND: undo
** COMMAND: redo*
**
** Usage: %fossil undo ?OPTIONS? ?FILENAME...?
**    or: %fossil redo ?OPTIONS? ?FILENAME...?
**
** Undo the changes to the working checkout caused by the most recent
** of the following operations:
**
**    (1) fossil update             (5) fossil stash apply
**    (2) fossil merge              (6) fossil stash drop
**    (3) fossil revert             (7) fossil stash goto
**    (4) fossil stash pop
**
** The "fossil clean" operation can also be undone; however, this is
** currently limited to files that are less than 10MiB in size.

**
** If FILENAME is specified then restore the content of the named
** file(s) but otherwise leave the update or merge or revert in effect.
** The redo command undoes the effect of the most recent undo.
**
** If the -n|--dry-run option is present, no changes are made and instead
** the undo or redo command explains what actions the undo or redo would
** have done had the -n|--dry-run been omitted.
**






** A single level of undo/redo is supported.  The undo/redo stack
** is cleared by the commit and checkout commands.




**
** Options:
**   -n|--dry-run   do not make changes but show what would be done
**
** See also: commit, status
*/
void undo_cmd(void){







|
|




|

|
|
>









>
>
>
>
>
>

|
>
>
>
>







421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
/*
** COMMAND: undo
** COMMAND: redo*
**
** Usage: %fossil undo ?OPTIONS? ?FILENAME...?
**    or: %fossil redo ?OPTIONS? ?FILENAME...?
**
** The undo command reverts the changes caused by the previous command
** if the previous command is one of the following:
**
**    (1) fossil update             (5) fossil stash apply
**    (2) fossil merge              (6) fossil stash drop
**    (3) fossil revert             (7) fossil stash goto
**    (4) fossil stash pop          (8) fossil clean  (*see note*)
**
** Note: The "fossil clean" command only saves state for files less than
** 10MiB in size and so if fossil clean deleted files larger than that,
** then "fossil undo" will not recover the larger files.
**
** If FILENAME is specified then restore the content of the named
** file(s) but otherwise leave the update or merge or revert in effect.
** The redo command undoes the effect of the most recent undo.
**
** If the -n|--dry-run option is present, no changes are made and instead
** the undo or redo command explains what actions the undo or redo would
** have done had the -n|--dry-run been omitted.
**
** If the most recent command is not one of those listed as undoable,
** then the undo command might try to restore the state to be what it was
** prior to the last undoable command, or it might be a no-op.  If in
** doubt about what the undo command will do, first run it with the -n
** option.
**
** A single level of undo/redo is supported.  The undo/redo stack
** is cleared by the commit and checkout commands.  Other commands may
** or may not clear the undo stack.
**
** Future versions of Fossil might add new commands to the set of commands
** that are undoable.
**
** Options:
**   -n|--dry-run   do not make changes but show what would be done
**
** See also: commit, status
*/
void undo_cmd(void){
Changes to src/unicode.c.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131

132
133
134
135
136
137
138
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153
    0x00217801, 0x00234C31, 0x0024E803, 0x0024F812, 0x00254407,
    0x00258804, 0x0025C001, 0x00260403, 0x0026F001, 0x0026F807,
    0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, 0x0027C802,
    0x0027E802, 0x0027F402, 0x00280403, 0x0028F001, 0x0028F805,
    0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D402,
    0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03,
    0x002B8802, 0x002BC002, 0x002BE806, 0x002C0403, 0x002CF001,
    0x002CF807, 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802,
    0x002DC001, 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804,
    0x002F5C01, 0x002FCC08, 0x00300005, 0x0030F807, 0x00311803,
    0x00312804, 0x00315402, 0x00318802, 0x0031DC01, 0x0031FC01,
    0x00320404, 0x0032F001, 0x0032F807, 0x00331803, 0x00332804,
    0x00335402, 0x00338802, 0x00340004, 0x0034EC02, 0x0034F807,
    0x00351803, 0x00352804, 0x00353C01, 0x00355C01, 0x00358802,
    0x0035E401, 0x00360802, 0x00372801, 0x00373C06, 0x00375801,
    0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, 0x0038FC01,
    0x00391C09, 0x00396802, 0x003AC401, 0x003AD009, 0x003B2006,
    0x003C041F, 0x003CD00C, 0x003DC417, 0x003E340B, 0x003E6424,
    0x003EF80F, 0x003F380D, 0x0040AC14, 0x00412806, 0x00415804,
    0x00417803, 0x00418803, 0x00419C07, 0x0041C404, 0x0042080C,
    0x00423C01, 0x00426806, 0x0043EC01, 0x004D740C, 0x004E400A,
    0x00500001, 0x0059B402, 0x005A0001, 0x005A6C02, 0x005BAC03,
    0x005C4803, 0x005CC805, 0x005D4802, 0x005DC802, 0x005ED023,
    0x005F6004, 0x005F7401, 0x0060000F, 0x00621402, 0x0062A401,
    0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, 0x00677822,
    0x00685C05, 0x00687802, 0x0069540A, 0x0069801D, 0x0069FC01,
    0x006A8007, 0x006AA006, 0x006AC00F, 0x006C0005, 0x006CD011,
    0x006D6823, 0x006E0003, 0x006E840D, 0x006F980E, 0x006FF004,
    0x00709014, 0x0070EC05, 0x0071F802, 0x00730008, 0x00734019,
    0x0073B401, 0x0073D001, 0x0073DC03, 0x0077003A, 0x0077EC05,
    0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, 0x007FB403,
    0x007FF402, 0x00800065, 0x0081980A, 0x0081E805, 0x00822805,
    0x00828020, 0x00834021, 0x00840002, 0x00840C04, 0x00842002,
    0x00845001, 0x00845803, 0x00847806, 0x00849401, 0x00849C01,
    0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, 0x00852804,
    0x00853C01, 0x00862802, 0x00864297, 0x0091000B, 0x0092704E,
    0x00940276, 0x009E53E0, 0x00ADD820, 0x00AE6068, 0x00B39406,
    0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, 0x00B5FC01,
    0x00B7804F, 0x00B8C020, 0x00BA001A, 0x00BA6C59, 0x00BC00D6,
    0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, 0x00C0D802,
    0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, 0x00C64002,
    0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, 0x00C94001,
    0x00C98020, 0x00CA2827, 0x00CB0140, 0x01370040, 0x02924037,
    0x0293F802, 0x02983403, 0x0299BC10, 0x029A7802, 0x029BC008,
    0x029C0017, 0x029C8002, 0x029E2402, 0x02A00801, 0x02A01801,
    0x02A02C01, 0x02A08C09, 0x02A0D804, 0x02A1D004, 0x02A20002,
    0x02A2D012, 0x02A33802, 0x02A38012, 0x02A3E003, 0x02A3F001,
    0x02A3FC01, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
    0x02A6CC1B, 0x02A77802, 0x02A79401, 0x02A8A40E, 0x02A90C01,
    0x02A93002, 0x02A97004, 0x02A9DC03, 0x02A9EC03, 0x02AAC001,
    0x02AAC803, 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802,
    0x02ABAC07, 0x02ABD402, 0x02AD6C01, 0x02AF8C0B, 0x03600001,
    0x036DFC02, 0x036FFC02, 0x037FFC01, 0x03EC7801, 0x03ECA401,
    0x03EEC810, 0x03F4F802, 0x03F7F002, 0x03F8001A, 0x03F88033,
    0x03F95013, 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807,
    0x03FCEC06, 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405,
    0x04040003, 0x0404DC09, 0x0405E411, 0x04063003, 0x0406400C,
    0x04068001, 0x0407402E, 0x040B8001, 0x040DD805, 0x040E7C01,
    0x040F4001, 0x0415BC01, 0x04215C01, 0x0421DC02, 0x04247C01,
    0x0424FC01, 0x04280403, 0x04281402, 0x04283004, 0x0428E003,
    0x0428FC01, 0x04294009, 0x0429FC01, 0x042B2001, 0x042B9402,
    0x042BC007, 0x042CE407, 0x042E6404, 0x04349004, 0x043D180B,
    0x043D5405, 0x04400003, 0x0440E016, 0x0441FC04, 0x0442C012,
    0x04433401, 0x04440003, 0x04449C0E, 0x04450004, 0x04451402,
    0x0445CC03, 0x04460003, 0x0446CC0E, 0x04471409, 0x04476C01,
    0x04477403, 0x0448B013, 0x044AA401, 0x044B7C0C, 0x044C0004,
    0x044CEC02, 0x044CF807, 0x044D1C02, 0x044D2C03, 0x044D5C01,
    0x044D8802, 0x044D9807, 0x044DC005, 0x0450D412, 0x04512C05,
    0x04516C01, 0x04517402, 0x0452C014, 0x04531801, 0x0456BC07,
    0x0456E020, 0x04577002, 0x0458C014, 0x0459800D, 0x045AAC0D,
    0x045C740F, 0x045CF004, 0x0460B010, 0x04674407, 0x04676807,

    0x04678801, 0x04679001, 0x0468040A, 0x0468CC07, 0x0468EC0D,
    0x0469440B, 0x046A2813, 0x046A7805, 0x0470BC08, 0x0470E008,
    0x04710405, 0x0471C002, 0x04724816, 0x0472A40E, 0x0474C406,
    0x0474E801, 0x0474F002, 0x0474FC07, 0x04751C01, 0x04762805,
    0x04764002, 0x04764C05, 0x047BCC06, 0x047F541D, 0x047FFC01,
    0x0491C005, 0x04D0C009, 0x05A9B802, 0x05ABC006, 0x05ACC010,
    0x05AD1002, 0x05BA5C04, 0x05BD3C01, 0x05BD4437, 0x05BE3C04,

    0x05BF8801, 0x06F27008, 0x074000F6, 0x07440027, 0x0744A4C0,
    0x07480046, 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01,
    0x075C5401, 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401,
    0x075EA401, 0x075F0C01, 0x0760028C, 0x076A6C05, 0x076A840F,
    0x07800007, 0x07802011, 0x07806C07, 0x07808C02, 0x07809805,
    0x0784C007, 0x07853C01, 0x078BB004, 0x078BFC01, 0x07A34007,
    0x07A51007, 0x07A57802, 0x07B2B001, 0x07B2C001, 0x07B4B801,
    0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, 0x07C2C40F,
    0x07C3040F, 0x07C34425, 0x07C4405D, 0x07C5C03D, 0x07C7981D,
    0x07C8402C, 0x07C90009, 0x07C94002, 0x07C98006, 0x07CC03D6,
    0x07DB800D, 0x07DBC00B, 0x07DC0074, 0x07DE0059, 0x07DF800C,
    0x07E0000C, 0x07E04038, 0x07E1400A, 0x07E18028, 0x07E2401E,
    0x07E4000C, 0x07E43465, 0x07E5CC04, 0x07E5E829, 0x07E69406,
    0x07E6B81D, 0x07E73487, 0x07E9800E, 0x07E9C004, 0x07E9E003,

    0x07EA0003, 0x07EA4006, 0x38000401, 0x38008060, 0x380400F0,
  };
  static const unsigned int aAscii[4] = {
    0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
  };

  if( (unsigned int)c<128 ){
    return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );







|






|











|









|

|






|





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







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153
154
155
    0x00217801, 0x00234C31, 0x0024E803, 0x0024F812, 0x00254407,
    0x00258804, 0x0025C001, 0x00260403, 0x0026F001, 0x0026F807,
    0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, 0x0027C802,
    0x0027E802, 0x0027F402, 0x00280403, 0x0028F001, 0x0028F805,
    0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D402,
    0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03,
    0x002B8802, 0x002BC002, 0x002BE806, 0x002C0403, 0x002CF001,
    0x002CF807, 0x002D1C02, 0x002D2C03, 0x002D5403, 0x002D8802,
    0x002DC001, 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804,
    0x002F5C01, 0x002FCC08, 0x00300005, 0x0030F807, 0x00311803,
    0x00312804, 0x00315402, 0x00318802, 0x0031DC01, 0x0031FC01,
    0x00320404, 0x0032F001, 0x0032F807, 0x00331803, 0x00332804,
    0x00335402, 0x00338802, 0x00340004, 0x0034EC02, 0x0034F807,
    0x00351803, 0x00352804, 0x00353C01, 0x00355C01, 0x00358802,
    0x0035E401, 0x00360403, 0x00372801, 0x00373C06, 0x00375801,
    0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, 0x0038FC01,
    0x00391C09, 0x00396802, 0x003AC401, 0x003AD009, 0x003B2006,
    0x003C041F, 0x003CD00C, 0x003DC417, 0x003E340B, 0x003E6424,
    0x003EF80F, 0x003F380D, 0x0040AC14, 0x00412806, 0x00415804,
    0x00417803, 0x00418803, 0x00419C07, 0x0041C404, 0x0042080C,
    0x00423C01, 0x00426806, 0x0043EC01, 0x004D740C, 0x004E400A,
    0x00500001, 0x0059B402, 0x005A0001, 0x005A6C02, 0x005BAC03,
    0x005C4803, 0x005CC805, 0x005D4802, 0x005DC802, 0x005ED023,
    0x005F6004, 0x005F7401, 0x0060000F, 0x00621402, 0x0062A401,
    0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, 0x00677822,
    0x00685C05, 0x00687802, 0x0069540A, 0x0069801D, 0x0069FC01,
    0x006A8007, 0x006AA006, 0x006AC011, 0x006C0005, 0x006CD011,
    0x006D6823, 0x006E0003, 0x006E840D, 0x006F980E, 0x006FF004,
    0x00709014, 0x0070EC05, 0x0071F802, 0x00730008, 0x00734019,
    0x0073B401, 0x0073D001, 0x0073DC03, 0x0077003A, 0x0077EC05,
    0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, 0x007FB403,
    0x007FF402, 0x00800065, 0x0081980A, 0x0081E805, 0x00822805,
    0x00828020, 0x00834021, 0x00840002, 0x00840C04, 0x00842002,
    0x00845001, 0x00845803, 0x00847806, 0x00849401, 0x00849C01,
    0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, 0x00852804,
    0x00853C01, 0x00862802, 0x00864297, 0x0091000B, 0x0092704E,
    0x00940276, 0x009E53E0, 0x00ADD820, 0x00AE5C69, 0x00B39406,
    0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, 0x00B5FC01,
    0x00B7804F, 0x00B8C023, 0x00BA001A, 0x00BA6C59, 0x00BC00D6,
    0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, 0x00C0D802,
    0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, 0x00C64002,
    0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, 0x00C94001,
    0x00C98020, 0x00CA2827, 0x00CB0140, 0x01370040, 0x02924037,
    0x0293F802, 0x02983403, 0x0299BC10, 0x029A7802, 0x029BC008,
    0x029C0017, 0x029C8002, 0x029E2402, 0x02A00801, 0x02A01801,
    0x02A02C01, 0x02A08C0A, 0x02A0D804, 0x02A1D004, 0x02A20002,
    0x02A2D012, 0x02A33802, 0x02A38012, 0x02A3E003, 0x02A3F001,
    0x02A3FC01, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
    0x02A6CC1B, 0x02A77802, 0x02A79401, 0x02A8A40E, 0x02A90C01,
    0x02A93002, 0x02A97004, 0x02A9DC03, 0x02A9EC03, 0x02AAC001,
    0x02AAC803, 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802,
    0x02ABAC07, 0x02ABD402, 0x02AD6C01, 0x02ADA802, 0x02AF8C0B,
    0x03600001, 0x036DFC02, 0x036FFC02, 0x037FFC01, 0x03EC7801,
    0x03ECA401, 0x03EEC810, 0x03F4F802, 0x03F7F002, 0x03F8001A,
    0x03F88033, 0x03F95013, 0x03F9A004, 0x03FBFC01, 0x03FC040F,
    0x03FC6807, 0x03FCEC06, 0x03FD6C0B, 0x03FF8007, 0x03FFA007,
    0x03FFE405, 0x04040003, 0x0404DC09, 0x0405E411, 0x04063003,
    0x0406400D, 0x04068001, 0x0407402E, 0x040B8001, 0x040DD805,
    0x040E7C01, 0x040F4001, 0x0415BC01, 0x04215C01, 0x0421DC02,
    0x04247C01, 0x0424FC01, 0x04280403, 0x04281402, 0x04283004,
    0x0428E003, 0x0428FC01, 0x04294009, 0x0429FC01, 0x042B2001,
    0x042B9402, 0x042BC007, 0x042CE407, 0x042E6404, 0x04349004,
    0x043AAC03, 0x043D180B, 0x043D5405, 0x04400003, 0x0440E016,
    0x0441FC04, 0x0442C012, 0x04433401, 0x04440003, 0x04449C0E,
    0x04450004, 0x04451402, 0x0445CC03, 0x04460003, 0x0446CC0E,
    0x0447140B, 0x04476C01, 0x04477403, 0x0448B013, 0x044AA401,
    0x044B7C0C, 0x044C0004, 0x044CEC02, 0x044CF807, 0x044D1C02,
    0x044D2C03, 0x044D5C01, 0x044D8802, 0x044D9807, 0x044DC005,
    0x0450D412, 0x04512C05, 0x04516802, 0x04517402, 0x0452C014,
    0x04531801, 0x0456BC07, 0x0456E020, 0x04577002, 0x0458C014,
    0x0459800D, 0x045AAC0D, 0x045C740F, 0x045CF004, 0x0460B010,
    0x0464C006, 0x0464DC02, 0x0464EC04, 0x04650001, 0x04650805,
    0x04674407, 0x04676807, 0x04678801, 0x04679001, 0x0468040A,
    0x0468CC07, 0x0468EC0D, 0x0469440B, 0x046A2813, 0x046A7805,
    0x0470BC08, 0x0470E008, 0x04710405, 0x0471C002, 0x04724816,
    0x0472A40E, 0x0474C406, 0x0474E801, 0x0474F002, 0x0474FC07,
    0x04751C01, 0x04762805, 0x04764002, 0x04764C05, 0x047BCC06,
    0x047F541D, 0x047FFC01, 0x0491C005, 0x04D0C009, 0x05A9B802,
    0x05ABC006, 0x05ACC010, 0x05AD1002, 0x05BA5C04, 0x05BD3C01,
    0x05BD4437, 0x05BE3C04, 0x05BF8801, 0x05BF9001, 0x05BFC002,
    0x06F27008, 0x074000F6, 0x07440027, 0x0744A4C0, 0x07480046,
    0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401,
    0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401,
    0x075F0C01, 0x0760028C, 0x076A6C05, 0x076A840F, 0x07800007,
    0x07802011, 0x07806C07, 0x07808C02, 0x07809805, 0x0784C007,
    0x07853C01, 0x078BB004, 0x078BFC01, 0x07A34007, 0x07A51007,
    0x07A57802, 0x07B2B001, 0x07B2C001, 0x07B4B801, 0x07BBC002,
    0x07C0002C, 0x07C0C064, 0x07C2800F, 0x07C2C40F, 0x07C3040F,
    0x07C34425, 0x07C434A1, 0x07C7981D, 0x07C8402C, 0x07C90009,
    0x07C94002, 0x07C98006, 0x07CC03D8, 0x07DB800D, 0x07DBC00D,
    0x07DC0074, 0x07DE0059, 0x07DF800C, 0x07E0000C, 0x07E04038,
    0x07E1400A, 0x07E18028, 0x07E2401E, 0x07E2C002, 0x07E40079,

    0x07E5E852, 0x07E73487, 0x07E9800E, 0x07E9C005, 0x07E9E003,
    0x07EA0007, 0x07EA4019, 0x07EAC007, 0x07EB0003, 0x07EB4007,
    0x07EC0093, 0x07EE5037, 0x38000401, 0x38008060, 0x380400F0,
  };
  static const unsigned int aAscii[4] = {
    0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
  };

  if( (unsigned int)c<128 ){
    return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );
348
349
350
351
352
353
354

355
356
357
358
359
360
361
362
    {42802, 1, 62},        {42873, 1, 4},         {42877, 98, 1},
    {42878, 1, 10},        {42891, 0, 1},         {42893, 88, 1},
    {42896, 1, 4},         {42902, 1, 20},        {42922, 80, 1},
    {42923, 76, 1},        {42924, 78, 1},        {42925, 84, 1},
    {42926, 80, 1},        {42928, 92, 1},        {42929, 86, 1},
    {42930, 90, 1},        {42931, 68, 1},        {42932, 1, 12},
    {42946, 0, 1},         {42948, 178, 1},       {42949, 82, 1},

    {42950, 96, 1},        {43888, 94, 80},       {65313, 14, 26},
  };
  static const unsigned short aiOff[] = {
   1,     2,     8,     15,    16,    26,    28,    32,
   34,    37,    38,    40,    48,    63,    64,    69,
   71,    79,    80,    116,   202,   203,   205,   206,
   207,   209,   210,   211,   213,   214,   217,   218,
   219,   775,   928,   7264,  10792, 10795, 23217, 23221,







>
|







350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
    {42802, 1, 62},        {42873, 1, 4},         {42877, 98, 1},
    {42878, 1, 10},        {42891, 0, 1},         {42893, 88, 1},
    {42896, 1, 4},         {42902, 1, 20},        {42922, 80, 1},
    {42923, 76, 1},        {42924, 78, 1},        {42925, 84, 1},
    {42926, 80, 1},        {42928, 92, 1},        {42929, 86, 1},
    {42930, 90, 1},        {42931, 68, 1},        {42932, 1, 12},
    {42946, 0, 1},         {42948, 178, 1},       {42949, 82, 1},
    {42950, 96, 1},        {42951, 1, 4},         {42997, 0, 1},
    {43888, 94, 80},       {65313, 14, 26},
  };
  static const unsigned short aiOff[] = {
   1,     2,     8,     15,    16,    26,    28,    32,
   34,    37,    38,    40,    48,    63,    64,    69,
   71,    79,    80,    116,   202,   203,   205,   206,
   207,   209,   210,   211,   213,   214,   217,   218,
   219,   775,   928,   7264,  10792, 10795, 23217, 23221,
Changes to src/unversioned.c.
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  Blob compressed;
  Blob hash;

  db_prepare(&ins,
    "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)"
    " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)"
  );
  sha1sum_blob(pContent, &hash);
  blob_compress(pContent, &compressed);
  db_bind_text(&ins, ":name", zUVFile);
  db_bind_int(&ins, ":rcvid", g.rcvid);
  db_bind_int64(&ins, ":mtime", mtime);
  db_bind_text(&ins, ":hash", blob_str(&hash));
  db_bind_int(&ins, ":sz", blob_size(pContent));
  if( blob_size(&compressed) <= 0.8*blob_size(pContent) ){







|







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  Blob compressed;
  Blob hash;

  db_prepare(&ins,
    "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)"
    " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)"
  );
  hname_hash(pContent, 0, &hash);
  blob_compress(pContent, &compressed);
  db_bind_text(&ins, ":name", zUVFile);
  db_bind_int(&ins, ":rcvid", g.rcvid);
  db_bind_int64(&ins, ":mtime", mtime);
  db_bind_text(&ins, ":hash", blob_str(&hash));
  db_bind_int(&ins, ":sz", blob_size(pContent));
  if( blob_size(&compressed) <= 0.8*blob_size(pContent) ){
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  db_finalize(&ins);
  db_unset("uv-hash", 0);
}


/*
** Check the status of unversioned file zName.  "mtime" and "zHash" are the
** time of last change and SHA1 hash of a copy of this file on a remote
** server.  Return an integer status code as follows:
**
**    0:     zName does not exist in the unversioned table.
**    1:     zName exists and should be replaced by the mtime/zHash remote.
**    2:     zName exists and is the same as zHash but has a older mtime
**    3:     zName exists and is identical to mtime/zHash in all respects.
**    4:     zName exists and is the same as zHash but has a newer mtime.







|







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  db_finalize(&ins);
  db_unset("uv-hash", 0);
}


/*
** Check the status of unversioned file zName.  "mtime" and "zHash" are the
** time of last change and hash of a copy of this file on a remote
** server.  Return an integer status code as follows:
**
**    0:     zName does not exist in the unversioned table.
**    1:     zName exists and should be replaced by the mtime/zHash remote.
**    2:     zName exists and is the same as zHash but has a older mtime
**    3:     zName exists and is identical to mtime/zHash in all respects.
**    4:     zName exists and is the same as zHash but has a newer mtime.
265
266
267
268
269
270
271

272
273
274
275
276
277
278
**
**    touch FILE ...         Update the TIMESTAMP on all of the listed files
**
** Options:
**
**   --mtime TIMESTAMP       Use TIMESTAMP instead of "now" for the "add",
**                           "edit", "remove", and "touch" subcommands.

*/
void unversioned_cmd(void){
  const char *zCmd;
  int nCmd;
  const char *zMtime = find_option("mtime", 0, 1);
  sqlite3_int64 mtime;
  db_find_and_open_repository(0, 0);







>







265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
**
**    touch FILE ...         Update the TIMESTAMP on all of the listed files
**
** Options:
**
**   --mtime TIMESTAMP       Use TIMESTAMP instead of "now" for the "add",
**                           "edit", "remove", and "touch" subcommands.
**   -R|--repository FILE    Use FILE as the repository
*/
void unversioned_cmd(void){
  const char *zCmd;
  int nCmd;
  const char *zMtime = find_option("mtime", 0, 1);
  sqlite3_int64 mtime;
  db_find_and_open_repository(0, 0);
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
      @ <table cellpadding="2" cellspacing="0" border="1" class='sortable' \
      @  data-column-types='tkKttn' data-init-sort='1'>
      @ <thead><tr>
      @   <th> Name
      @   <th> Age
      @   <th> Size
      @   <th> User
      @   <th> SHA1
      if( g.perm.Admin ){
        @ <th> rcvid
      }
      @ </tr></thead>
      @ <tbody>
    }
    @ <tr>







|







525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
      @ <table cellpadding="2" cellspacing="0" border="1" class='sortable' \
      @  data-column-types='tkKttn' data-init-sort='1'>
      @ <thead><tr>
      @   <th> Name
      @   <th> Age
      @   <th> Size
      @   <th> User
      @   <th> Hash
      if( g.perm.Admin ){
        @ <th> rcvid
      }
      @ </tr></thead>
      @ <tbody>
    }
    @ <tr>
Changes to src/update.c.
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
**   -v|--verbose     print status information about all files
**   -W|--width <num> Width of lines (default is to auto-detect). Must be >20
**                    or 0 (= no limit, resulting in a single line per entry).
**   --setmtime       Set timestamps of all files to match their SCM-side
**                    times (the timestamp of the last checkin which modified
**                    them).
**




** See also: revert
*/
void update_cmd(void){
  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 dryRunFlag;       /* -n or --dry-run.  Do a dry run */
  int verboseFlag;      /* -v or --verbose.  Output extra information */
  int forceMissingFlag; /* --force-missing.  Continue if missing content */
  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 changes of any kind */
  int width;            /* Width of printed comment lines */







>
>
>
>












>







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
**   -v|--verbose     print status information about all files
**   -W|--width <num> Width of lines (default is to auto-detect). Must be >20
**                    or 0 (= no limit, resulting in a single line per entry).
**   --setmtime       Set timestamps of all files to match their SCM-side
**                    times (the timestamp of the last checkin which modified
**                    them).
**
**  -K|--keep-merge-files  On merge conflict, retain the temporary files
**                         used for merging, named *-baseline, *-original,
**                         and *-merge.
**
** See also: revert
*/
void update_cmd(void){
  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 dryRunFlag;       /* -n or --dry-run.  Do a dry run */
  int verboseFlag;      /* -v or --verbose.  Output extra information */
  int forceMissingFlag; /* --force-missing.  Continue if missing content */
  int debugFlag;        /* --debug option */
  int setmtimeFlag;     /* --setmtime.  Set mtimes on files */
  int keepMergeFlag;    /* True if --keep-merge-files is present */
  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 changes of any kind */
  int width;            /* Width of printed comment lines */
145
146
147
148
149
150
151

152
153
154
155
156
157
158
  if( !dryRunFlag ){
    dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */
  }
  verboseFlag = find_option("verbose","v",0)!=0;
  forceMissingFlag = find_option("force-missing",0,0)!=0;
  debugFlag = find_option("debug",0,0)!=0;
  setmtimeFlag = find_option("setmtime",0,0)!=0;


  /* We should be done with options.. */
  verify_all_options();

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







>







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  if( !dryRunFlag ){
    dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */
  }
  verboseFlag = find_option("verbose","v",0)!=0;
  forceMissingFlag = find_option("force-missing",0,0)!=0;
  debugFlag = find_option("debug",0,0)!=0;
  setmtimeFlag = find_option("setmtime",0,0)!=0;
  keepMergeFlag = find_option("keep-merge-files", "K",0)!=0;

  /* We should be done with options.. */
  verify_all_options();

  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);
  user_select();
488
489
490
491
492
493
494

495
496
497
498
499
500
501
        fossil_print("MERGE %s\n", zName);
      }
      if( islinkv || islinkt ){
        fossil_print("***** Cannot merge symlink %s\n", zNewName);
        nConflict++;
      }else{
        unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;

        if( !dryRunFlag && !internalUpdate ) undo_save(zName);
        content_get(ridt, &t);
        content_get(ridv, &v);
        rc = merge_3way(&v, zFullPath, &t, &r, mergeFlags);
        if( rc>=0 ){
          if( !dryRunFlag ){
            blob_write_to_file(&r, zFullNewPath);







>







494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
        fossil_print("MERGE %s\n", zName);
      }
      if( islinkv || islinkt ){
        fossil_print("***** Cannot merge symlink %s\n", zNewName);
        nConflict++;
      }else{
        unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
        if(keepMergeFlag!=0) mergeFlags |= MERGE_KEEP_FILES;
        if( !dryRunFlag && !internalUpdate ) undo_save(zName);
        content_get(ridt, &t);
        content_get(ridv, &v);
        rc = merge_3way(&v, zFullPath, &t, &r, mergeFlags);
        if( rc>=0 ){
          if( !dryRunFlag ){
            blob_write_to_file(&r, zFullNewPath);
679
680
681
682
683
684
685

686
687
688
689
690
691
692
  if( zRevision ){
    vid = name_to_typed_rid(zRevision, "ci");
  }else if( !g.localOpen ){
    vid = name_to_typed_rid(db_get("main-branch", 0), "ci");
  }else{
    vid = db_lget_int("checkout", 0);
    if( !is_a_version(vid) ){

      zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
      if( zRevision ){
        fossil_fatal("checkout artifact is not a check-in: %s", zRevision);
      }else{
        fossil_fatal("invalid checkout artifact ID: %d", vid);
      }
    }







>







686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
  if( zRevision ){
    vid = name_to_typed_rid(zRevision, "ci");
  }else if( !g.localOpen ){
    vid = name_to_typed_rid(db_get("main-branch", 0), "ci");
  }else{
    vid = db_lget_int("checkout", 0);
    if( !is_a_version(vid) ){
      if( vid==0 ) return 0;
      zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
      if( zRevision ){
        fossil_fatal("checkout artifact is not a check-in: %s", zRevision);
      }else{
        fossil_fatal("invalid checkout artifact ID: %d", vid);
      }
    }
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
    int vid = db_lget_int("checkout", 0);
    zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
  }
  while( db_step(&q)==SQLITE_ROW ){
    char *zFull;
    zFile = db_column_text(&q, 0);
    zFull = mprintf("%/%/", g.zLocalRoot, zFile);
    pRvFile = manifest_file_find(pRvManifest, zFile);
    if( !pRvFile ){
      if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
                 zFile, zFile)==0 ){
        fossil_print("UNMANAGE %s\n", zFile);
      }else{
        undo_save(zFile);
        file_delete(zFull);







|







857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
    int vid = db_lget_int("checkout", 0);
    zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
  }
  while( db_step(&q)==SQLITE_ROW ){
    char *zFull;
    zFile = db_column_text(&q, 0);
    zFull = mprintf("%/%/", g.zLocalRoot, zFile);
    pRvFile = pRvManifest? manifest_file_find(pRvManifest, zFile) : 0;
    if( !pRvFile ){
      if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
                 zFile, zFile)==0 ){
        fossil_print("UNMANAGE %s\n", zFile);
      }else{
        undo_save(zFile);
        file_delete(zFull);
Changes to src/url.c.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  int useProxy;    /* Used to remember that a proxy is in use */
  char *proxyUrlPath;
  int proxyOrigPort; /* Tunneled port number for https through proxy */
};
#endif /* INTERFACE */


/*
** Convert a string to lower-case.
*/
static void url_tolower(char *z){
  while( *z ){
     *z = fossil_tolower(*z);
     z++;
  }
}

/*
** Parse the given URL.  Populate members of the provided UrlData structure
** as follows:
**
**      isFile      True if FILE:
**      isHttps     True if HTTPS:
**      isSsh       True if SSH:







<
<
<
<
<
<
<
<
<
<







64
65
66
67
68
69
70










71
72
73
74
75
76
77
  int useProxy;    /* Used to remember that a proxy is in use */
  char *proxyUrlPath;
  int proxyOrigPort; /* Tunneled port number for https through proxy */
};
#endif /* INTERFACE */












/*
** Parse the given URL.  Populate members of the provided UrlData structure
** as follows:
**
**      isFile      True if FILE:
**      isHttps     True if HTTPS:
**      isSsh       True if SSH:
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
      n = strlen(pUrlData->name);
      if( pUrlData->name[0]=='[' && n>2 && pUrlData->name[n-1]==']' ){
        pUrlData->name++;
        pUrlData->name[n-2] = 0;
      }
      zLogin = mprintf("");
    }
    url_tolower(pUrlData->name);
    if( c==':' ){
      pUrlData->port = 0;
      i++;
      while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
        pUrlData->port = pUrlData->port*10 + c - '0';
        i++;
      }







|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
      n = strlen(pUrlData->name);
      if( pUrlData->name[0]=='[' && n>2 && pUrlData->name[n-1]==']' ){
        pUrlData->name++;
        pUrlData->name[n-2] = 0;
      }
      zLogin = mprintf("");
    }
    fossil_strtolwr(pUrlData->name);
    if( c==':' ){
      pUrlData->port = 0;
      i++;
      while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
        pUrlData->port = pUrlData->port*10 + c - '0';
        i++;
      }
Changes to src/utf8.c.
296
297
298
299
300
301
302





















































303
304
305
306
307
308
309
  sqlite3_free(pOld);
#elif (defined(__APPLE__) && !defined(WITHOUT_ICONV)) || defined(__CYGWIN__)
  fossil_free(pOld);
#else
  /* No-op on all other unix */
#endif
}






















































/*
** Display UTF-8 on the console.  Return the number of
** Characters written. If stdout or stderr is redirected
** to a file, -1 is returned and nothing is written
** to the console.
*/







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







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
  sqlite3_free(pOld);
#elif (defined(__APPLE__) && !defined(WITHOUT_ICONV)) || defined(__CYGWIN__)
  fossil_free(pOld);
#else
  /* No-op on all other unix */
#endif
}

/*
** For a given index in a UTF-8 string, return the nearest index that is the
** start of a new code point. The returned index is equal or lower than the
** given index. The end of the string (the null-terminator) is considered a
** valid start index. The given index is returned unchanged if the string
** contains invalid UTF-8 (i.e. overlong runs of trail bytes).
** This function is useful to find code point boundaries for truncation, for
** example, so that no incomplete UTF-8 sequences are left at the end of the
** truncated string.
** This function does not attempt to keep logical and/or visual constructs
** spanning across multiple code points intact, that is no attempts are made
** keep combining characters together with their base characters, or to keep
** more complex grapheme clusters intact.
*/
#define IsUTF8TrailByte(c) ( (c&0xc0)==0x80 )
int utf8_nearest_codepoint(const char *zString, int maxByteIndex){
  int i,n;
  for( n=0, i=maxByteIndex; n<4 && i>=0; n++, i-- ){
    if( !IsUTF8TrailByte(zString[i]) ) return i;
  }
  return maxByteIndex;
}

/*
** Find the byte index corresponding to the given code point index in a UTF-8
** string. If the string contains fewer than the given number of code points,
** the index of the end of the string (the null-terminator) is returned.
** Incomplete, ill-formed and overlong sequences are counted as one sequence.
** The invalid lead bytes 0xC0 to 0xC1 and 0xF5 to 0xF7 are allowed to initiate
** (ill-formed) 2- and 4-byte sequences, respectively, the other invalid lead
** bytes 0xF8 to 0xFF are treated as invalid 1-byte sequences (as lone trail
** bytes).
*/
int utf8_codepoint_index(const char *zString, int nCodePoint){
  int i;       /* Counted bytes. */
  int lenUTF8; /* Counted UTF-8 sequences. */
  if( zString==0 ) return 0;
  for(i=0, lenUTF8=0; zString[i]!=0 && lenUTF8<nCodePoint; i++, lenUTF8++){
    char c = zString[i];
    int cchUTF8=1; /* Code units consumed. */
    int maxUTF8=1; /* Expected sequence length. */
    if( (c&0xe0)==0xc0 )maxUTF8=2;          /* UTF-8 lead byte 110vvvvv */
    else if( (c&0xf0)==0xe0 )maxUTF8=3;     /* UTF-8 lead byte 1110vvvv */
    else if( (c&0xf8)==0xf0 )maxUTF8=4;     /* UTF-8 lead byte 11110vvv */
    while( cchUTF8<maxUTF8 &&
            (zString[i+1]&0xc0)==0x80 ){    /* UTF-8 trail byte 10vvvvvv */
      cchUTF8++;
      i++;
    }
  }
  return i;
}

/*
** Display UTF-8 on the console.  Return the number of
** Characters written. If stdout or stderr is redirected
** to a file, -1 is returned and nothing is written
** to the console.
*/
Changes to src/util.c.
138
139
140
141
142
143
144















145
146
147
148
149
150
151
  if( munmap(p, n) ){
    fossil_panic("munmap failed: %d\n", errno);
  }
#else
  fossil_free(p);
#endif
}
















/*
** This function implements a cross-platform "system()" interface.
*/
int fossil_system(const char *zOrigCmd){
  int rc;
#if defined(_WIN32)







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







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
  if( munmap(p, n) ){
    fossil_panic("munmap failed: %d\n", errno);
  }
#else
  fossil_free(p);
#endif
}

/*
** Translate every upper-case character in the input string into
** its equivalent lower-case.
*/
char *fossil_strtolwr(char *zIn){
  char *zStart = zIn;
  if( zIn ){
    while( *zIn ){
      *zIn = fossil_tolower(*zIn);
      zIn++;
    }
  }
  return zStart;
}

/*
** This function implements a cross-platform "system()" interface.
*/
int fossil_system(const char *zOrigCmd){
  int rc;
#if defined(_WIN32)
Changes to src/verify.c.
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
** This routine is called just prior to each commit operation.
**
** Invoke verify_rid() on every record that has been added or modified
** in the repository, in order to make sure that the repository is sane.
*/
static int verify_at_commit(void){
  int rid;
  content_clear_cache();
  inFinalVerify = 1;
  rid = bag_first(&toVerify);
  while( rid>0 ){
    verify_rid(rid);
    rid = bag_next(&toVerify, rid);
  }
  bag_clear(&toVerify);







|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
** This routine is called just prior to each commit operation.
**
** Invoke verify_rid() on every record that has been added or modified
** in the repository, in order to make sure that the repository is sane.
*/
static int verify_at_commit(void){
  int rid;
  content_clear_cache(0);
  inFinalVerify = 1;
  rid = bag_first(&toVerify);
  while( rid>0 ){
    verify_rid(rid);
    rid = bag_next(&toVerify, rid);
  }
  bag_clear(&toVerify);
Changes to src/wiki.c.
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
  style_header("Wiki Search");
  wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
  search_screen(SRCH_WIKI, 0);
  style_footer();
}

/* Return values from wiki_page_type() */

#define WIKITYPE_UNKNOWN    (-1)
#define WIKITYPE_NORMAL     0
#define WIKITYPE_BRANCH     1
#define WIKITYPE_CHECKIN    2
#define WIKITYPE_TAG        3


/*
** Figure out what type of wiki page we are dealing with.
*/
static int wiki_page_type(const char *zPageName){
  if( db_get_boolean("wiki-about",1)==0 ){
    return WIKITYPE_NORMAL;
  }else
  if( sqlite3_strglob("checkin/*", zPageName)==0 
   && db_exists("SELECT 1 FROM blob WHERE uuid=%Q",zPageName+8)
  ){
    return WIKITYPE_CHECKIN;
  }else
  if( sqlite3_strglob("branch/*", zPageName)==0 ){
    return WIKITYPE_BRANCH;
  }else
  if( sqlite3_strglob("tag/*", zPageName)==0 ){
    return WIKITYPE_TAG;
  }
  return WIKITYPE_NORMAL;
}

/*
** Add an appropriate style_header() for either the /wiki or /wikiedit page
** for zPageName.






*/
static int wiki_page_header(
  int eType,                /* Page type.  -1 for unknown */
  const char *zPageName,    /* Name of the page */
  const char *zExtra        /* Extra prefix text on the page header */
){
  if( eType<0 ) eType = wiki_page_type(zPageName);
  switch( eType ){
    case WIKITYPE_NORMAL: {
      style_header("%s%s", zExtra, zPageName);
      break;
    }
    case WIKITYPE_CHECKIN: {
      zPageName += 8;



      style_header("Notes About Checkin %S", zPageName);
      style_submenu_element("Checkin Timeline","%R/timeline?f=%s", zPageName);
      style_submenu_element("Checkin Info","%R/info/%s", zPageName);

      break;
    }
    case WIKITYPE_BRANCH: {
      zPageName += 7;



      style_header("Notes About Branch %h", zPageName);
      style_submenu_element("Branch Timeline","%R/timeline?r=%t", zPageName);

      break;
    }
    case WIKITYPE_TAG: {
      zPageName += 4;



      style_header("Notes About Tag %h", zPageName);
      style_submenu_element("Tag Timeline","%R/timeline?t=%t",zPageName);

      break;
    }
  }
  return eType;
}

/*







>
|
|
|
|
|
>




|



















|
>
>
>
>
>
>


|



|







>
>
>
|
|
|
>




>
>
>
|
|
>




>
>
>
|
|
>







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
450
451
452
453
454
455
  style_header("Wiki Search");
  wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
  search_screen(SRCH_WIKI, 0);
  style_footer();
}

/* Return values from wiki_page_type() */
#if INTERFACE
# define WIKITYPE_UNKNOWN    (-1)
# define WIKITYPE_NORMAL     0
# define WIKITYPE_BRANCH     1
# define WIKITYPE_CHECKIN    2
# define WIKITYPE_TAG        3
#endif

/*
** Figure out what type of wiki page we are dealing with.
*/
int wiki_page_type(const char *zPageName){
  if( db_get_boolean("wiki-about",1)==0 ){
    return WIKITYPE_NORMAL;
  }else
  if( sqlite3_strglob("checkin/*", zPageName)==0 
   && db_exists("SELECT 1 FROM blob WHERE uuid=%Q",zPageName+8)
  ){
    return WIKITYPE_CHECKIN;
  }else
  if( sqlite3_strglob("branch/*", zPageName)==0 ){
    return WIKITYPE_BRANCH;
  }else
  if( sqlite3_strglob("tag/*", zPageName)==0 ){
    return WIKITYPE_TAG;
  }
  return WIKITYPE_NORMAL;
}

/*
** Add an appropriate style_header() for either the /wiki or /wikiedit page
** for zPageName.  zExtra is an empty string for /wiki but has the text
** "Edit: " for /wikiedit.
**
** If the page is /wiki and the page is one of the special times (check-in,
** branch, or tag) and the "p" query parameter is omitted, then do a 
** redirect to the display of the check-in, branch, or tag rather than
** continuing to the plain wiki display.
*/
static int wiki_page_header(
  int eType,                /* Page type.  Might be WIKITYPE_UNKNOWN */
  const char *zPageName,    /* Name of the page */
  const char *zExtra        /* Extra prefix text on the page header */
){
  if( eType==WIKITYPE_UNKNOWN ) eType = wiki_page_type(zPageName);
  switch( eType ){
    case WIKITYPE_NORMAL: {
      style_header("%s%s", zExtra, zPageName);
      break;
    }
    case WIKITYPE_CHECKIN: {
      zPageName += 8;
      if( zExtra[0]==0 && !P("p") ){
        cgi_redirectf("%R/info/%s",zPageName);
      }else{
        style_header("Notes About Checkin %S", zPageName);
        style_submenu_element("Checkin Timeline","%R/timeline?f=%s", zPageName);
        style_submenu_element("Checkin Info","%R/info/%s", zPageName);
      }
      break;
    }
    case WIKITYPE_BRANCH: {
      zPageName += 7;
      if( zExtra[0]==0 && !P("p") ){
        cgi_redirectf("%R/timeline?r=%t", zPageName);
      }else{
        style_header("Notes About Branch %h", zPageName);
        style_submenu_element("Branch Timeline","%R/timeline?r=%t", zPageName);
      }
      break;
    }
    case WIKITYPE_TAG: {
      zPageName += 4;
      if( zExtra[0]==0 && !P("p") ){
        cgi_redirectf("%R/timeline?t=%t",zPageName);
      }else{
        style_header("Notes About Tag %h", zPageName);
        style_submenu_element("Tag Timeline","%R/timeline?t=%t",zPageName);
      }
      break;
    }
  }
  return eType;
}

/*
450
451
452
453
454
455
456

457









458
459
460
461
462
463
464
465
466
467
468

469
470
471
472
473
474
475
    return 1;
  }
  return g.perm.Write;
}

/*
** WEBPAGE: wiki

** URL: /wiki?name=PAGENAME









*/
void wiki_page(void){
  char *zTag;
  int rid = 0;
  int isSandbox;
  unsigned submenuFlags = W_HELP;
  Blob wiki;
  Manifest *pWiki = 0;
  const char *zPageName;
  const char *zMimetype = 0;
  char *zBody = mprintf("%s","<i>Empty Page</i>");


  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  zPageName = P("name");
  if( zPageName==0 ){
    if( search_restrict(SRCH_WIKI)!=0 ){
      wiki_srchpage();







>
|
>
>
>
>
>
>
>
>
>











>







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
    return 1;
  }
  return g.perm.Write;
}

/*
** WEBPAGE: wiki
**
** Display a wiki page.  Example:  /wiki?name=PAGENAME
**
** Query parameters:
**
**    name=NAME        Name of the wiki page to display.  Required.
**    nsm              Omit the submenu if present.  (Mnemonic: No SubMenu)
**    p                Always show just the wiki page.  For special
**                     pages for check-ins, branches, or tags, there will
**                     be a redirect to the associated /info page unless
**                     this query parameter is present.
*/
void wiki_page(void){
  char *zTag;
  int rid = 0;
  int isSandbox;
  unsigned submenuFlags = W_HELP;
  Blob wiki;
  Manifest *pWiki = 0;
  const char *zPageName;
  const char *zMimetype = 0;
  char *zBody = mprintf("%s","<i>Empty Page</i>");
  int noSubmenu = P("nsm")!=0;

  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  zPageName = P("name");
  if( zPageName==0 ){
    if( search_restrict(SRCH_WIKI)!=0 ){
      wiki_srchpage();
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

525

526
527
528
529
530
531
532
    pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
    if( pWiki ){
      zBody = pWiki->zWiki;
      zMimetype = pWiki->zMimetype;
    }
  }
  zMimetype = wiki_filter_mimetypes(zMimetype);
  if( !g.isHome ){
    if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki))
     && wiki_special_permission(zPageName)
    ){
      if( db_get_boolean("wysiwyg-wiki", 0) ){
        style_submenu_element("Edit", "%R/wikiedit?name=%T&wysiwyg=1",
                              zPageName);
      }else{
        style_submenu_element("Edit", "%R/wikiedit?name=%T", zPageName);
      }
    }else if( rid && g.perm.ApndWiki ){
      style_submenu_element("Edit", "%R/wikiappend?name=%T", zPageName);
    }
    if( g.perm.Hyperlink ){
      style_submenu_element("History", "%R/whistory?name=%T", zPageName);
    }
  }
  style_set_current_page("%T?name=%T", g.zPath, zPageName);
  wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "");

  wiki_standard_submenu(submenuFlags);

  if( zBody[0]==0 ){
    @ <i>This page has been deleted</i>
  }else{
    blob_init(&wiki, zBody, -1);
    wiki_render_by_mimetype(&wiki, zMimetype);
    blob_reset(&wiki);
  }







|


















>
|
>







530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
    pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
    if( pWiki ){
      zBody = pWiki->zWiki;
      zMimetype = pWiki->zMimetype;
    }
  }
  zMimetype = wiki_filter_mimetypes(zMimetype);
  if( !g.isHome && !noSubmenu ){
    if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki))
     && wiki_special_permission(zPageName)
    ){
      if( db_get_boolean("wysiwyg-wiki", 0) ){
        style_submenu_element("Edit", "%R/wikiedit?name=%T&wysiwyg=1",
                              zPageName);
      }else{
        style_submenu_element("Edit", "%R/wikiedit?name=%T", zPageName);
      }
    }else if( rid && g.perm.ApndWiki ){
      style_submenu_element("Edit", "%R/wikiappend?name=%T", zPageName);
    }
    if( g.perm.Hyperlink ){
      style_submenu_element("History", "%R/whistory?name=%T", zPageName);
    }
  }
  style_set_current_page("%T?name=%T", g.zPath, zPageName);
  wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "");
  if( !noSubmenu ){
    wiki_standard_submenu(submenuFlags);
  }
  if( zBody[0]==0 ){
    @ <i>This page has been deleted</i>
  }else{
    blob_init(&wiki, zBody, -1);
    wiki_render_by_mimetype(&wiki, zMimetype);
    blob_reset(&wiki);
  }
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
      zWDisplayName = mprintf("%s", zWName);
    }
    if( wrid==0 ){
      if( !showAll ) continue;
      @ <tr><td data-sortkey="%h(zSort)">\
      @ %z(href("%R/whistory?name=%T",zWName))<s>%h(zWDisplayName)</s></a></td>
    }else{
      @ <tr><td data=sortkey='%h(zSort)">\
      @ %z(href("%R/wiki?name=%T",zWName))%h(zWDisplayName)</a></td>
    }
    zAge = human_readable_age(rNow - rWmtime);
    @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td>
    fossil_free(zAge);
    @ <td>%z(href("%R/whistory?name=%T",zWName))%d(wcnt)</a></td>
    if( showRid ){







|







1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
      zWDisplayName = mprintf("%s", zWName);
    }
    if( wrid==0 ){
      if( !showAll ) continue;
      @ <tr><td data-sortkey="%h(zSort)">\
      @ %z(href("%R/whistory?name=%T",zWName))<s>%h(zWDisplayName)</s></a></td>
    }else{
      @ <tr><td data-sortkey="%h(zSort)">\
      @ %z(href("%R/wiki?name=%T",zWName))%h(zWDisplayName)</a></td>
    }
    zAge = human_readable_age(rNow - rWmtime);
    @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td>
    fossil_free(zAge);
    @ <td>%z(href("%R/whistory?name=%T",zWName))%d(wcnt)</a></td>
    if( showRid ){
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392




1393
1394


1395
1396







1397
1398
1399
1400
1401
1402
1403
/*
** COMMAND: wiki*
**
** Usage: %fossil wiki (export|create|commit|list) WikiName
**
** Run various subcommands to work with wiki entries or tech notes.
**
**    %fossil wiki export PAGENAME ?FILE?
**    %fossil wiki export ?FILE? -t|--technote DATETIME|TECHNOTE-ID
**
**       Sends the latest version of either a wiki page or of a tech note
**       to the given file or standard output.




**       If PAGENAME is provided, the wiki page will be output. For
**       a tech note either DATETIME or TECHNOTE-ID must be specified. If


**       DATETIME is used, the most recently modified tech note with that
**       DATETIME will be sent.







**
**    %fossil wiki (create|commit) PAGENAME ?FILE? ?OPTIONS?
**
**       Create a new or commit changes to an existing wiki page or
**       technote from FILE or from standard input. PAGENAME is the
**       name of the wiki entry or the timeline comment of the
**       technote.







|
|

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







1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
/*
** COMMAND: wiki*
**
** Usage: %fossil wiki (export|create|commit|list) WikiName
**
** Run various subcommands to work with wiki entries or tech notes.
**
**    %fossil wiki export ?OPTIONS? PAGENAME ?FILE?
**    %fossil wiki export ?OPTIONS? -t|--technote DATETIME|TECHNOTE-ID ?FILE?
**
**       Sends the latest version of either a wiki page or of a tech
**       note to the given file or standard output.  A filename of "-"
**       writes the output to standard output.  The directory parts of
**       the output filename are created if needed.
**
**    Options:
**       If PAGENAME is provided, the named wiki page will be output.
**       --technote|-t DATETIME|TECHNOTE-ID
**                  Specifies that a technote, rather than a wiki page,
**                  will be exported. If DATETIME is used, the most
**                  recently modified tech note with that DATETIME will
**                  output.
**       -h|--html  The body (only) is rendered in HTML form, without
**                  any page header/foot or HTML/BODY tag wrappers.
**       -H|--HTML  Works like -h|-html but wraps the output in
**                  <html><body>...</body></html>.
**       -p|--pre   If -h|-H is used and the page or technote has
**                  the text/plain mimetype, its HTML-escaped output
**                  will be wrapped in <pre>...</pre>.
**
**    %fossil wiki (create|commit) PAGENAME ?FILE? ?OPTIONS?
**
**       Create a new or commit changes to an existing wiki page or
**       technote from FILE or from standard input. PAGENAME is the
**       name of the wiki entry or the timeline comment of the
**       technote.
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470









1471

1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490

1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507

1508




1509


































1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523

1524
1525
1526
1527
1528
1529
1530
  if( strncmp(g.argv[2],"export",n)==0 ){
    const char *zPageName;        /* Name of the wiki page to export */
    const char *zFile;            /* Name of the output file (0=stdout) */
    const char *zETime;           /* The name of the technote to export */
    int rid;                      /* Artifact ID of the wiki page */
    int i;                        /* Loop counter */
    char *zBody = 0;              /* Wiki page content */
    Blob body;                    /* Wiki page content */
    Manifest *pWiki = 0;          /* Parsed wiki page content */










    zETime = find_option("technote","t",1);

    if( !zETime ){
      if( (g.argc!=4) && (g.argc!=5) ){
        usage("export PAGENAME ?FILE?");
      }
      zPageName = g.argv[3];
      rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
        " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
        " ORDER BY x.mtime DESC LIMIT 1",
        zPageName
      );
      if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
        zBody = pWiki->zWiki;
      }
      if( zBody==0 ){
        fossil_fatal("wiki page [%s] not found",zPageName);
      }
      zFile = (g.argc==4) ? "-" : g.argv[4];
    }else{
      if( (g.argc!=3) && (g.argc!=4) ){

        usage("export ?FILE? --technote DATETIME|TECHNOTE-ID");
      }
      rid = wiki_technote_to_rid(zETime);
      if ( rid==-1 ){
        fossil_fatal("ambiguous tech note id: %s", zETime);
      }
      if( (pWiki = manifest_get(rid, CFTYPE_EVENT, 0))!=0 ){
        zBody = pWiki->zWiki;
      }
      if( zBody==0 ){
        fossil_fatal("technote [%s] not found",zETime);
      }
      zFile = (g.argc==3) ? "-" : g.argv[3];
    }
    for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){}
    zBody[i] = 0;
    blob_init(&body, zBody, -1);

    blob_append(&body, "\n", 1);




    blob_write_to_file(&body, zFile);


































    blob_reset(&body);
    manifest_destroy(pWiki);
    return;
  }else if( strncmp(g.argv[2],"commit",n)==0
            || strncmp(g.argv[2],"create",n)==0 ){
    const char *zPageName;        /* page name */
    Blob content;                 /* Input content */
    int rid = 0;
    Manifest *pWiki = 0;          /* Parsed wiki page content */
    const int isCreate = 'r'==g.argv[2][1] /* else "commit" */;
    const char *zMimeType = find_option("mimetype", "M", 1);
    const char *zETime = find_option("technote", "t", 1);
    const char *zTags = find_option("technote-tags", NULL, 1);
    const char *zClr = find_option("technote-bgcolor", NULL, 1);

    if( g.argc!=4 && g.argc!=5 ){
      usage("commit|create PAGENAME ?FILE? [--mimetype TEXT-FORMAT]"
            " [--technote DATETIME] [--technote-tags TAGS]"
            " [--technote-bgcolor COLOR]");
    }
    zPageName = g.argv[3];
    if( g.argc==4 ){







|

|
>
>
>
>
>
>
>
>
>

>


|
















>
|
















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














>







1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
  if( strncmp(g.argv[2],"export",n)==0 ){
    const char *zPageName;        /* Name of the wiki page to export */
    const char *zFile;            /* Name of the output file (0=stdout) */
    const char *zETime;           /* The name of the technote to export */
    int rid;                      /* Artifact ID of the wiki page */
    int i;                        /* Loop counter */
    char *zBody = 0;              /* Wiki page content */
    Blob body = empty_blob;       /* Wiki page content */
    Manifest *pWiki = 0;          /* Parsed wiki page content */
    int fHtml = 0;                /* Export in HTML form */
    FILE * pFile = 0;             /* Output file */
    int fPre = 0;                 /* Indicates that -h|-H should be
                                  ** wrapped in <pre>...</pre> if pWiki
                                  ** has the text/plain mimetype. */
    fHtml = find_option("HTML","H",0)!=0
      ? 2
      : (find_option("html","h",0)!=0 ? 1 : 0)
      /* 1 == -html, 2 == -HTML */;
    fPre = fHtml==0 ? 0 : find_option("pre","p",0)!=0;
    zETime = find_option("technote","t",1);
    verify_all_options();
    if( !zETime ){
      if( (g.argc!=4) && (g.argc!=5) ){
        usage("export ?-html? PAGENAME ?FILE?");
      }
      zPageName = g.argv[3];
      rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
        " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
        " ORDER BY x.mtime DESC LIMIT 1",
        zPageName
      );
      if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
        zBody = pWiki->zWiki;
      }
      if( zBody==0 ){
        fossil_fatal("wiki page [%s] not found",zPageName);
      }
      zFile = (g.argc==4) ? "-" : g.argv[4];
    }else{
      if( (g.argc!=3) && (g.argc!=4) ){
        usage("export ?-html? ?FILE? --technote "
              "DATETIME|TECHNOTE-ID");
      }
      rid = wiki_technote_to_rid(zETime);
      if ( rid==-1 ){
        fossil_fatal("ambiguous tech note id: %s", zETime);
      }
      if( (pWiki = manifest_get(rid, CFTYPE_EVENT, 0))!=0 ){
        zBody = pWiki->zWiki;
      }
      if( zBody==0 ){
        fossil_fatal("technote [%s] not found",zETime);
      }
      zFile = (g.argc==3) ? "-" : g.argv[3];
    }
    for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){}
    zBody[i] = 0;
    blob_init(&body, zBody, -1);
    if(fHtml==0){
      blob_append(&body, "\n", 1);
    }else{
      Blob html = empty_blob;   /* HTML-ized content */
      const char * zMimetype = wiki_filter_mimetypes(pWiki->zMimetype);
      if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
        wiki_convert(&body,&html,0);
      }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
        markdown_to_html(&body,0,&html)
          /* TODO: add -HTML|-H flag to work like -html|-h but also
          ** add <html><body> tag wrappers around the output. The
          ** hurdle here is that the markdown converter resets its
          ** input blob before appending the output, which is
          ** different from wiki_convert() and htmlize_to_blob(), and
          ** precludes us simply appending the opening <html><body>
          ** part to the body
          */;
      }else if( fossil_strcmp(zMimetype, "text/plain")==0 ){
        htmlize_to_blob(&html,zBody,i);
      }else{
        fossil_fatal("Unsupported MIME type '%s' for wiki page '%s'.",
                     zMimetype, pWiki->zWikiTitle );
      }
      blob_reset(&body);
      body = html /* transfer memory */;
    }
    pFile = fossil_fopen_for_output(zFile);
    if(fHtml==2){
      fwrite("<html><body>", 1, 12, pFile);
    }
    if(fPre!=0){
      fwrite("<pre>", 1, 5, pFile);
    }
    fwrite(blob_buffer(&body), 1, blob_size(&body), pFile);
    if(fPre!=0){
      fwrite("</pre>", 1, 6, pFile);
    }
    if(fHtml==2){
      fwrite("</body></html>\n", 1, 15, pFile);
    }
    fossil_fclose(pFile);
    blob_reset(&body);
    manifest_destroy(pWiki);
    return;
  }else if( strncmp(g.argv[2],"commit",n)==0
            || strncmp(g.argv[2],"create",n)==0 ){
    const char *zPageName;        /* page name */
    Blob content;                 /* Input content */
    int rid = 0;
    Manifest *pWiki = 0;          /* Parsed wiki page content */
    const int isCreate = 'r'==g.argv[2][1] /* else "commit" */;
    const char *zMimeType = find_option("mimetype", "M", 1);
    const char *zETime = find_option("technote", "t", 1);
    const char *zTags = find_option("technote-tags", NULL, 1);
    const char *zClr = find_option("technote-bgcolor", NULL, 1);
    verify_all_options();
    if( g.argc!=4 && g.argc!=5 ){
      usage("commit|create PAGENAME ?FILE? [--mimetype TEXT-FORMAT]"
            " [--technote DATETIME] [--technote-tags TAGS]"
            " [--technote-bgcolor COLOR]");
    }
    zPageName = g.argv[3];
    if( g.argc==4 ){
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607

1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
      }else{
        fossil_fatal("ambiguous tech note id: %s", zETime);
      }
    }
    manifest_destroy(pWiki);
    blob_reset(&content);
  }else if( strncmp(g.argv[2],"delete",n)==0 ){
    if( g.argc!=5 ){
      usage("delete PAGENAME");
    }
    fossil_fatal("delete not yet implemented.");
  }else if(( strncmp(g.argv[2],"list",n)==0 )
          || ( strncmp(g.argv[2],"ls",n)==0 )){
    Stmt q;

    int showIds = 0;

    if ( !find_option("technote","t",0) ){
      db_prepare(&q,
        "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'"
        " ORDER BY lower(tagname) /*sort*/"
      );
    }else{
      showIds = find_option("show-technote-ids","s",0)!=0;
      db_prepare(&q,
        "SELECT datetime(e.mtime), substr(t.tagname,7)"
         " FROM event e, tag t"
        " WHERE e.type='e'"
          " AND e.tagid IS NOT NULL"
          " AND t.tagid=e.tagid"
        " ORDER BY e.mtime DESC /*sort*/"
      );
    }

    while( db_step(&q)==SQLITE_ROW ){
      const char *zName = db_column_text(&q, 0);
      if( showIds ){
        const char *zUuid = db_column_text(&q, 1);
        fossil_print("%s ",zUuid);
      }
      fossil_print( "%s\n",zName);







|






>
|
|
|





<









<







1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713

1714
1715
1716
1717
1718
1719
1720
1721
1722

1723
1724
1725
1726
1727
1728
1729
      }else{
        fossil_fatal("ambiguous tech note id: %s", zETime);
      }
    }
    manifest_destroy(pWiki);
    blob_reset(&content);
  }else if( strncmp(g.argv[2],"delete",n)==0 ){
    if( g.argc!=4 ){
      usage("delete PAGENAME");
    }
    fossil_fatal("delete not yet implemented.");
  }else if(( strncmp(g.argv[2],"list",n)==0 )
          || ( strncmp(g.argv[2],"ls",n)==0 )){
    Stmt q;
    const int fTechnote = find_option("technote","t",0)!=0;
    const int showIds = find_option("show-technote-ids","s",0)!=0;
    verify_all_options();
    if (fTechnote==0){
      db_prepare(&q,
        "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'"
        " ORDER BY lower(tagname) /*sort*/"
      );
    }else{

      db_prepare(&q,
        "SELECT datetime(e.mtime), substr(t.tagname,7)"
         " FROM event e, tag t"
        " WHERE e.type='e'"
          " AND e.tagid IS NOT NULL"
          " AND t.tagid=e.tagid"
        " ORDER BY e.mtime DESC /*sort*/"
      );
    }

    while( db_step(&q)==SQLITE_ROW ){
      const char *zName = db_column_text(&q, 0);
      if( showIds ){
        const char *zUuid = db_column_text(&q, 1);
        fossil_print("%s ",zUuid);
      }
      fossil_print( "%s\n",zName);
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
*/
static void wiki_section_label(
  const char *zPrefix,   /* "branch", "tag", or "checkin" */
  const char *zName,     /* Name of the object */
  unsigned int mFlags    /* Zero or more WIKIASSOC_* flags */
){
  if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){
    @ <div class="section">About</div>
  }else if( zPrefix[0]=='c' ){  /* checkin/... */
    @ <div class="section">About checkin %.20h(zName)</div>
  }else{
    @ <div class="section">About %s(zPrefix) %h(zName)</div>
  }
}

/*
** Add an "Wiki" button in a submenu that links to the read-wiki page.
*/
static void wiki_submenu_to_read_wiki(
  const char *zPrefix,   /* "branch", "tag", or "checkin" */
  const char *zName,     /* Name of the object */
  unsigned int mFlags    /* Zero or more WIKIASSOC_* flags */
){
  if( g.perm.RdWiki && (mFlags & WIKIASSOC_MENU_READ)!=0 ){
    style_submenu_element("Wiki", "%R/wiki?name=%s/%t", zPrefix, zName);
  }
}

/*
** Check to see if there exists a wiki page with a name zPrefix/zName.
** If there is, then render a <div class='section'>..</div> and
** return true.







|

|

|






|





|







1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
*/
static void wiki_section_label(
  const char *zPrefix,   /* "branch", "tag", or "checkin" */
  const char *zName,     /* Name of the object */
  unsigned int mFlags    /* Zero or more WIKIASSOC_* flags */
){
  if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){
    @ <div class="section accordion">About</div>
  }else if( zPrefix[0]=='c' ){  /* checkin/... */
    @ <div class="section accordion">About checkin %.20h(zName)</div>
  }else{
    @ <div class="section accordion">About %s(zPrefix) %h(zName)</div>
  }
}

/*
** Add an "Wiki" button in a submenu that links to the read-wiki page.
*/
static void wiki_submenu_to_edit_wiki(
  const char *zPrefix,   /* "branch", "tag", or "checkin" */
  const char *zName,     /* Name of the object */
  unsigned int mFlags    /* Zero or more WIKIASSOC_* flags */
){
  if( g.perm.RdWiki && (mFlags & WIKIASSOC_MENU_READ)!=0 ){
    style_submenu_element("Wiki", "%R/wikiedit?name=%s/%t", zPrefix, zName);
  }
}

/*
** Check to see if there exists a wiki page with a name zPrefix/zName.
** If there is, then render a <div class='section'>..</div> and
** return true.
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725

1726

1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757

1758
1759
  if( fossil_strcmp(pWiki->zMimetype, "text/x-markdown")==0 ){
    Blob tail = BLOB_INITIALIZER;
    Blob title = BLOB_INITIALIZER;
    Blob markdown;
    blob_init(&markdown, pWiki->zWiki, -1);
    markdown_to_html(&markdown, &title, &tail);
    if( blob_size(&title) ){
      @ <div class="section">%h(blob_str(&title))</div>
    }else{
      wiki_section_label(zPrefix, zName, mFlags);
    }
    wiki_submenu_to_read_wiki(zPrefix, zName, mFlags);

    convert_href_and_output(&tail);

    blob_reset(&tail);
    blob_reset(&title);
    blob_reset(&markdown);
  }else if( fossil_strcmp(pWiki->zMimetype, "text/plain")==0 ){
    wiki_section_label(zPrefix, zName, mFlags);
    wiki_submenu_to_read_wiki(zPrefix, zName, mFlags);
    @ <pre>
    @ %h(pWiki->zWiki)
    @ </pre>
  }else{
    Blob tail = BLOB_INITIALIZER;
    Blob title = BLOB_INITIALIZER;
    Blob wiki;
    Blob *pBody;
    blob_init(&wiki, pWiki->zWiki, -1);
    if( wiki_find_title(&wiki, &title, &tail) ){
      @ <div class="section">%h(blob_str(&title))</div>
      pBody = &tail;
    }else{
      wiki_section_label(zPrefix, zName, mFlags);
      pBody = &wiki;
    }
    wiki_submenu_to_read_wiki(zPrefix, zName, mFlags);
    @ <div class="wiki">
    wiki_convert(pBody, 0, WIKI_BUTTONS);
    @ </div>
    blob_reset(&tail);
    blob_reset(&title);
    blob_reset(&wiki);
  }
  manifest_destroy(pWiki);

  return 1;
}







|



|
>

>





|
|

|







|





|
|

|





>


1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
  if( fossil_strcmp(pWiki->zMimetype, "text/x-markdown")==0 ){
    Blob tail = BLOB_INITIALIZER;
    Blob title = BLOB_INITIALIZER;
    Blob markdown;
    blob_init(&markdown, pWiki->zWiki, -1);
    markdown_to_html(&markdown, &title, &tail);
    if( blob_size(&title) ){
      @ <div class="section accordion">%h(blob_str(&title))</div>
    }else{
      wiki_section_label(zPrefix, zName, mFlags);
    }
    wiki_submenu_to_edit_wiki(zPrefix, zName, mFlags);
    @ <div class="accordion_panel">
    convert_href_and_output(&tail);
    @ </div>
    blob_reset(&tail);
    blob_reset(&title);
    blob_reset(&markdown);
  }else if( fossil_strcmp(pWiki->zMimetype, "text/plain")==0 ){
    wiki_section_label(zPrefix, zName, mFlags);
    wiki_submenu_to_edit_wiki(zPrefix, zName, mFlags);
    @ <div class="accordion_panel"><pre>
    @ %h(pWiki->zWiki)
    @ </pre></div>
  }else{
    Blob tail = BLOB_INITIALIZER;
    Blob title = BLOB_INITIALIZER;
    Blob wiki;
    Blob *pBody;
    blob_init(&wiki, pWiki->zWiki, -1);
    if( wiki_find_title(&wiki, &title, &tail) ){
      @ <div class="section accordion">%h(blob_str(&title))</div>
      pBody = &tail;
    }else{
      wiki_section_label(zPrefix, zName, mFlags);
      pBody = &wiki;
    }
    wiki_submenu_to_edit_wiki(zPrefix, zName, mFlags);
    @ <div class="accordion_panel"><div class="wiki">
    wiki_convert(pBody, 0, WIKI_BUTTONS);
    @ </div></div>
    blob_reset(&tail);
    blob_reset(&title);
    blob_reset(&wiki);
  }
  manifest_destroy(pWiki);
  style_accordion();
  return 1;
}
Changes to src/wikiformat.c.
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112

/*
** zTarget is guaranteed to be a UUID.  It might be the UUID of a ticket.
** If it is, store in *pClosed a true or false depending on whether or not
** the ticket is closed and return true. If zTarget
** is not the UUID of a ticket, return false.
*/
static int is_ticket(
  const char *zTarget,    /* Ticket UUID */
  int *pClosed            /* True if the ticket is closed */
){
  static Stmt q;
  int n;
  int rc;
  char zLower[HNAME_MAX+1];







|







1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112

/*
** zTarget is guaranteed to be a UUID.  It might be the UUID of a ticket.
** If it is, store in *pClosed a true or false depending on whether or not
** the ticket is closed and return true. If zTarget
** is not the UUID of a ticket, return false.
*/
int is_ticket(
  const char *zTarget,    /* Ticket UUID */
  int *pClosed            /* True if the ticket is closed */
){
  static Stmt q;
  int n;
  int rc;
  char zLower[HNAME_MAX+1];
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
**
** Where "target" can be either an artifact ID prefix or a wiki page
** name.  For each such hyperlink found, add an entry to the
** backlink table.
*/
void wiki_extract_links(
  char *z,           /* The wiki text from which to extract links */
  int srcid,         /* srcid field for new BACKLINK table entries */
  int srctype,       /* srctype field for new BACKLINK table entries */
  double mtime,      /* mtime field for new BACKLINK table entries */
  int replaceFlag,   /* True first delete prior BACKLINK entries */
  int flags          /* wiki parsing flags */
){
  Renderer renderer;
  int tokenType;
  ParsedMarkup markup;
  int n;
  int inlineOnly;
  int wikiHtmlOnly = 0;

  memset(&renderer, 0, sizeof(renderer));
  renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
  if( flags & WIKI_NOBLOCK ){
    renderer.state |= INLINE_MARKUP_ONLY;
  }
  if( wikiUsesHtml() ){
    renderer.state |= WIKI_HTMLONLY;
    wikiHtmlOnly = 1;
  }
  inlineOnly = (renderer.state & INLINE_MARKUP_ONLY)!=0;
  if( replaceFlag ){
    db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
                  srctype, srcid);
  }

  while( z[0] ){
    if( wikiHtmlOnly ){
      n = nextRawToken(z, &renderer, &tokenType);
    }else{
      n = nextWikiToken(z, &renderer, &tokenType);
    }
    switch( tokenType ){
      case TOKEN_LINK: {
        char *zTarget;
        int i, c;
        char zLink[HNAME_MAX+4];

        zTarget = &z[1];
        for(i=0; zTarget[i] && zTarget[i]!='|' && zTarget[i]!=']'; i++){}
        while(i>1 && zTarget[i-1]==' '){ i--; }
        c = zTarget[i];
        zTarget[i] = 0;
        if( is_valid_hname(zTarget) ){
          memcpy(zLink, zTarget, i+1);
          canonical16(zLink, i);
          db_multi_exec(
             "REPLACE INTO backlink(target,srctype,srcid,mtime)"
             "VALUES(%Q,%d,%d,%g)", zLink, srctype, srcid, mtime
          );
        }
        zTarget[i] = c;
        break;
      }
      case TOKEN_MARKUP: {
        const char *zId;
        int iDiv;
        parseMarkup(&markup, z);








|
<
<
<



















<
<
<
<










|
<




<
<
<
|
<
<
<
<
<
<
<







1867
1868
1869
1870
1871
1872
1873
1874



1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893




1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904

1905
1906
1907
1908



1909







1910
1911
1912
1913
1914
1915
1916
**
** Where "target" can be either an artifact ID prefix or a wiki page
** name.  For each such hyperlink found, add an entry to the
** backlink table.
*/
void wiki_extract_links(
  char *z,           /* The wiki text from which to extract links */
  Backlink *pBklnk,  /* Backlink extraction context */



  int flags          /* wiki parsing flags */
){
  Renderer renderer;
  int tokenType;
  ParsedMarkup markup;
  int n;
  int inlineOnly;
  int wikiHtmlOnly = 0;

  memset(&renderer, 0, sizeof(renderer));
  renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
  if( flags & WIKI_NOBLOCK ){
    renderer.state |= INLINE_MARKUP_ONLY;
  }
  if( wikiUsesHtml() ){
    renderer.state |= WIKI_HTMLONLY;
    wikiHtmlOnly = 1;
  }
  inlineOnly = (renderer.state & INLINE_MARKUP_ONLY)!=0;





  while( z[0] ){
    if( wikiHtmlOnly ){
      n = nextRawToken(z, &renderer, &tokenType);
    }else{
      n = nextWikiToken(z, &renderer, &tokenType);
    }
    switch( tokenType ){
      case TOKEN_LINK: {
        char *zTarget;
        int i;


        zTarget = &z[1];
        for(i=0; zTarget[i] && zTarget[i]!='|' && zTarget[i]!=']'; i++){}
        while(i>1 && zTarget[i-1]==' '){ i--; }



        backlink_create(pBklnk, zTarget, i);







        break;
      }
      case TOKEN_MARKUP: {
        const char *zId;
        int iDiv;
        parseMarkup(&markup, z);

Changes to src/xfer.c.
37
38
39
40
41
42
43

44
45
46
47
48
49
50
51
52
53
54


55
56
57
58
59
60
61
  Blob *pIn;          /* Input text from the other side */
  Blob *pOut;         /* Compose our reply here */
  Blob line;          /* The current line of input */
  Blob aToken[6];     /* Tokenized version of line */
  Blob err;           /* Error message text */
  int nToken;         /* Number of tokens in line */
  int nIGotSent;      /* Number of "igot" cards sent */

  int nGimmeSent;     /* Number of gimme cards sent */
  int nFileSent;      /* Number of files sent */
  int nDeltaSent;     /* Number of deltas sent */
  int nFileRcvd;      /* Number of files received */
  int nDeltaRcvd;     /* Number of deltas received */
  int nDanglingFile;  /* Number of dangling deltas received */
  int mxSend;         /* Stop sending "file" when pOut reaches this size */
  int resync;         /* Send igot cards for all holdings */
  u8 syncPrivate;     /* True to enable syncing private content */
  u8 nextIsPrivate;   /* If true, next "file" received is a private */
  u32 clientVersion;  /* Version of the client software */


  time_t maxTime;     /* Time when this transfer should be finished */
};


/*
** The input blob contains an artifact.  Convert it into a record ID.
** Create a phantom record if no prior record exists and







>










|
>
>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  Blob *pIn;          /* Input text from the other side */
  Blob *pOut;         /* Compose our reply here */
  Blob line;          /* The current line of input */
  Blob aToken[6];     /* Tokenized version of line */
  Blob err;           /* Error message text */
  int nToken;         /* Number of tokens in line */
  int nIGotSent;      /* Number of "igot" cards sent */
  int nPrivIGot;      /* Number of private "igot" cards */
  int nGimmeSent;     /* Number of gimme cards sent */
  int nFileSent;      /* Number of files sent */
  int nDeltaSent;     /* Number of deltas sent */
  int nFileRcvd;      /* Number of files received */
  int nDeltaRcvd;     /* Number of deltas received */
  int nDanglingFile;  /* Number of dangling deltas received */
  int mxSend;         /* Stop sending "file" when pOut reaches this size */
  int resync;         /* Send igot cards for all holdings */
  u8 syncPrivate;     /* True to enable syncing private content */
  u8 nextIsPrivate;   /* If true, next "file" received is a private */
  u32 remoteVersion;  /* Version of fossil running on the other side */
  u32 remoteDate;     /* Date for specific client software edition */
  u32 remoteTime;     /* Time of date correspoding on remoteDate */
  time_t maxTime;     /* Time when this transfer should be finished */
};


/*
** The input blob contains an artifact.  Convert it into a record ID.
** Create a phantom record if no prior record exists and
522
523
524
525
526
527
528
529












530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
** this routine becomes a no-op.
*/
static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int nativeDelta){
  Blob content, uuid;
  int size = 0;
  int isPriv = content_is_private(rid);

  if( pXfer->syncPrivate==0 && isPriv ) return;












  if( db_exists("SELECT 1 FROM onremote WHERE rid=%d", rid) ){
     return;
  }
  blob_zero(&uuid);
  db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d AND size>=0", rid);
  if( blob_size(&uuid)==0 ){
    return;
  }
  if( blob_size(&uuid)>HNAME_LEN_SHA1 && pXfer->clientVersion<20000 ){
    xfer_cannot_send_sha3_error(pXfer);
    return;
  }
  if( pUuid ){
    if( blob_compare(pUuid, &uuid)!=0 ){
      blob_reset(&uuid);
      return;







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








|







525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
** this routine becomes a no-op.
*/
static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int nativeDelta){
  Blob content, uuid;
  int size = 0;
  int isPriv = content_is_private(rid);

  if( isPriv && pXfer->syncPrivate==0 ){
    if( pXfer->remoteDate>=20200413 && pUuid && blob_size(pUuid)>0 ){
      /* If the artifact is private and we are not doing a private sync,
      ** at least tell the other side that the artifact exists and is
      ** known to be private.  But only do this for newer clients since
      ** older ones will throw an error if they get a private igot card
      ** and private syncing is disallowed */
      blob_appendf(pXfer->pOut, "igot %b 1\n", pUuid);
      pXfer->nIGotSent++;
      pXfer->nPrivIGot++;
    }
    return;
  }
  if( db_exists("SELECT 1 FROM onremote WHERE rid=%d", rid) ){
     return;
  }
  blob_zero(&uuid);
  db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d AND size>=0", rid);
  if( blob_size(&uuid)==0 ){
    return;
  }
  if( blob_size(&uuid)>HNAME_LEN_SHA1 && pXfer->remoteVersion<20000 ){
    xfer_cannot_send_sha3_error(pXfer);
    return;
  }
  if( pUuid ){
    if( blob_compare(pUuid, &uuid)!=0 ){
      blob_reset(&uuid);
      return;
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
    zUuid = db_column_text(&q1, 0);
    szU = db_column_int(&q1, 1);
    szC = db_column_bytes(&q1, 2);
    zContent = db_column_raw(&q1, 2);
    srcIsPrivate = db_column_int(&q1, 3);
    zDelta = db_column_text(&q1, 4);
    if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1);
    if( pXfer->clientVersion<20000 && db_column_bytes(&q1,0)!=HNAME_LEN_SHA1 ){
      xfer_cannot_send_sha3_error(pXfer);
      db_reset(&q1);
      return;
    }
    blob_appendf(pXfer->pOut, "cfile %s ", zUuid);
    if( !isPrivate && srcIsPrivate ){
      content_get(rid, &fullContent);







|







639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
    zUuid = db_column_text(&q1, 0);
    szU = db_column_int(&q1, 1);
    szC = db_column_bytes(&q1, 2);
    zContent = db_column_raw(&q1, 2);
    srcIsPrivate = db_column_int(&q1, 3);
    zDelta = db_column_text(&q1, 4);
    if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1);
    if( pXfer->remoteVersion<20000 && db_column_bytes(&q1,0)!=HNAME_LEN_SHA1 ){
      xfer_cannot_send_sha3_error(pXfer);
      db_reset(&q1);
      return;
    }
    blob_appendf(pXfer->pOut, "cfile %s ", zUuid);
    if( !isPrivate && srcIsPrivate ){
      content_get(rid, &fullContent);
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
      " WHERE name=%Q",
      zName
    );
  }
  if( db_step(&q1)==SQLITE_ROW ){
    sqlite3_int64 mtime = db_column_int64(&q1, 0);
    const char *zHash = db_column_text(&q1, 1);
    if( pXfer->clientVersion<20000 && db_column_bytes(&q1,1)>HNAME_LEN_SHA1 ){
      xfer_cannot_send_sha3_error(pXfer);
      db_reset(&q1);
      return;
    }
    if( blob_size(pXfer->pOut)>=pXfer->mxSend ){
      /* If we have already reached the send size limit, send a (short)
      ** uvigot card rather than a uvfile card.  This only happens on the







|







703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
      " WHERE name=%Q",
      zName
    );
  }
  if( db_step(&q1)==SQLITE_ROW ){
    sqlite3_int64 mtime = db_column_int64(&q1, 0);
    const char *zHash = db_column_text(&q1, 1);
    if( pXfer->remoteVersion<20000 && db_column_bytes(&q1,1)>HNAME_LEN_SHA1 ){
      xfer_cannot_send_sha3_error(pXfer);
      db_reset(&q1);
      return;
    }
    if( blob_size(pXfer->pOut)>=pXfer->mxSend ){
      /* If we have already reached the send size limit, send a (short)
      ** uvigot card rather than a uvfile card.  This only happens on the
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
  }
  return cnt;
}

/*
** Send an igot message for every entry in unclustered table.
** Return the number of cards sent.











*/
static int send_unclustered(Xfer *pXfer){
  Stmt q;
  int cnt = 0;






  if( pXfer->resync ){
    db_prepare(&q,
      "SELECT uuid, rid FROM blob"
      " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
      "   AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
      "   AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
      "   AND blob.rid<=%d"
      " ORDER BY blob.rid DESC",
      pXfer->resync
    );
  }else{
    db_prepare(&q,
      "SELECT uuid FROM unclustered JOIN blob USING(rid) /*scan*/"
      " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
      "   AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
      "   AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"

    );
  }
  while( db_step(&q)==SQLITE_ROW ){
    blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
    cnt++;
    if( pXfer->resync && pXfer->mxSend<blob_size(pXfer->pOut) ){
      pXfer->resync = db_column_int(&q, 1)-1;







>
>
>
>
>
>
>
>
>
>
>




>
>
>
>
>
>





|


|






|
>







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
1014
1015
1016
1017
1018
1019
1020
  }
  return cnt;
}

/*
** Send an igot message for every entry in unclustered table.
** Return the number of cards sent.
**
** Except:
**    *  Do not send igot cards for shunned artifacts
**    *  Do not send igot cards for phantoms
**    *  Do not send igot cards for private artifacts
**    *  Do not send igot cards for any artifact that is in the
**       ONREMOTE table, if that table exists.
**
** If the pXfer->resync flag is set, that means we are doing a "--verily"
** sync and all artifacts that don't meet the restrictions above should
** be sent.
*/
static int send_unclustered(Xfer *pXfer){
  Stmt q;
  int cnt = 0;
  const char *zExtra;
  if( db_table_exists("temp","onremote") ){
    zExtra = " AND NOT EXISTS(SELECT 1 FROM onremote WHERE rid=blob.rid)";
  }else{
    zExtra = "";
  }
  if( pXfer->resync ){
    db_prepare(&q,
      "SELECT uuid, rid FROM blob"
      " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
      "   AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
      "   AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)%s"
      "   AND blob.rid<=%d"
      " ORDER BY blob.rid DESC",
      zExtra /*safe-for-%s*/, pXfer->resync
    );
  }else{
    db_prepare(&q,
      "SELECT uuid FROM unclustered JOIN blob USING(rid) /*scan*/"
      " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
      "   AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
      "   AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)%s",
      zExtra /*safe-for-%s*/
    );
  }
  while( db_step(&q)==SQLITE_ROW ){
    blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
    cnt++;
    if( pXfer->resync && pXfer->mxSend<blob_size(pXfer->pOut) ){
      pXfer->resync = db_column_int(&q, 1)-1;
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286


1287

1288
1289



1290

1291











1292



1293
1294
1295
1296
1297
1298
1299
    if( blob_buffer(&xfer.line)[0]=='#' ) continue;
    if( blob_size(&xfer.line)==0 ) continue;
    xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));

    /*   file HASH SIZE \n CONTENT
    **   file HASH DELTASRC SIZE \n CONTENT
    **
    ** Accept a file from the client.
    */
    if( blob_eq(&xfer.aToken[0], "file") ){
      if( !isPush ){
        cgi_reset_content();
        @ error not\sauthorized\sto\swrite
        nErr++;
        break;
      }
      xfer_accept_file(&xfer, 0, pzUuidList, pnUuidList);
      if( blob_size(&xfer.err) ){
        cgi_reset_content();
        @ error %T(blob_str(&xfer.err))
        nErr++;
        break;
      }
    }else

    /*   cfile HASH USIZE CSIZE \n CONTENT
    **   cfile HASH DELTASRC USIZE CSIZE \n CONTENT
    **
    ** Accept a file from the client.
    */
    if( blob_eq(&xfer.aToken[0], "cfile") ){
      if( !isPush ){
        cgi_reset_content();
        @ error not\sauthorized\sto\swrite
        nErr++;
        break;
      }
      xfer_accept_compressed_file(&xfer, pzUuidList, pnUuidList);
      if( blob_size(&xfer.err) ){
        cgi_reset_content();
        @ error %T(blob_str(&xfer.err))
        nErr++;
        break;
      }
    }else

    /*   uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
    **
    ** Accept an unversioned file from the client.
    */
    if( blob_eq(&xfer.aToken[0], "uvfile") ){
      xfer_accept_unversioned_file(&xfer, g.perm.WrUnver);
      if( blob_size(&xfer.err) ){
        cgi_reset_content();
        @ error %T(blob_str(&xfer.err))
        nErr++;
        break;
      }
    }else

    /*   gimme HASH
    **
    ** Client is requesting a file.  Send it.
    */
    if( blob_eq(&xfer.aToken[0], "gimme")
     && xfer.nToken==2
     && blob_is_hname(&xfer.aToken[1])
    ){
      nGimme++;
      if( isPull ){
        int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
        if( rid ){
          send_file(&xfer, rid, &xfer.aToken[1], deltaFlag);
        }
      }
    }else

    /*   uvgimme NAME
    **
    ** Client is requesting an unversioned file.  Send it.
    */
    if( blob_eq(&xfer.aToken[0], "uvgimme")
     && xfer.nToken==2
     && blob_is_filename(&xfer.aToken[1])
    ){
      send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0);
    }else

    /*   igot HASH ?ISPRIVATE?
    **
    ** Client announces that it has a particular file.  If the ISPRIVATE
    ** argument exists and is non-zero, then the file is a private file.
    */
    if( xfer.nToken>=2
     && blob_eq(&xfer.aToken[0], "igot")
     && blob_is_hname(&xfer.aToken[1])
    ){
      if( isPush ){


        if( xfer.nToken==2 || blob_eq(&xfer.aToken[2],"1")==0 ){

          rid_from_uuid(&xfer.aToken[1], 1, 0);
        }else if( g.perm.Private ){



          rid_from_uuid(&xfer.aToken[1], 1, 1);

        }else{











          server_private_xfer_not_authorized();



        }
      }
    }else


    /*    pull  SERVERCODE  PROJECTCODE
    **    push  SERVERCODE  PROJECTCODE







|




















|



















|













|
















|











|






>
>

>
|

>
>
>
|
>

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







1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
    if( blob_buffer(&xfer.line)[0]=='#' ) continue;
    if( blob_size(&xfer.line)==0 ) continue;
    xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));

    /*   file HASH SIZE \n CONTENT
    **   file HASH DELTASRC SIZE \n CONTENT
    **
    ** Server accepts a file from the client.
    */
    if( blob_eq(&xfer.aToken[0], "file") ){
      if( !isPush ){
        cgi_reset_content();
        @ error not\sauthorized\sto\swrite
        nErr++;
        break;
      }
      xfer_accept_file(&xfer, 0, pzUuidList, pnUuidList);
      if( blob_size(&xfer.err) ){
        cgi_reset_content();
        @ error %T(blob_str(&xfer.err))
        nErr++;
        break;
      }
    }else

    /*   cfile HASH USIZE CSIZE \n CONTENT
    **   cfile HASH DELTASRC USIZE CSIZE \n CONTENT
    **
    ** Server accepts a compressed file from the client.
    */
    if( blob_eq(&xfer.aToken[0], "cfile") ){
      if( !isPush ){
        cgi_reset_content();
        @ error not\sauthorized\sto\swrite
        nErr++;
        break;
      }
      xfer_accept_compressed_file(&xfer, pzUuidList, pnUuidList);
      if( blob_size(&xfer.err) ){
        cgi_reset_content();
        @ error %T(blob_str(&xfer.err))
        nErr++;
        break;
      }
    }else

    /*   uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
    **
    ** Server accepts an unversioned file from the client.
    */
    if( blob_eq(&xfer.aToken[0], "uvfile") ){
      xfer_accept_unversioned_file(&xfer, g.perm.WrUnver);
      if( blob_size(&xfer.err) ){
        cgi_reset_content();
        @ error %T(blob_str(&xfer.err))
        nErr++;
        break;
      }
    }else

    /*   gimme HASH
    **
    ** Client is requesting a file from the server.  Send it.
    */
    if( blob_eq(&xfer.aToken[0], "gimme")
     && xfer.nToken==2
     && blob_is_hname(&xfer.aToken[1])
    ){
      nGimme++;
      if( isPull ){
        int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
        if( rid ){
          send_file(&xfer, rid, &xfer.aToken[1], deltaFlag);
        }
      }
    }else

    /*   uvgimme NAME
    **
    ** Client is requesting an unversioned file from the server.  Send it.
    */
    if( blob_eq(&xfer.aToken[0], "uvgimme")
     && xfer.nToken==2
     && blob_is_filename(&xfer.aToken[1])
    ){
      send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0);
    }else

    /*   igot HASH ?ISPRIVATE?
    **
    ** Client announces that it has a particular file.  If the ISPRIVATE
    ** argument exists and is "1", then the file is a private file.
    */
    if( xfer.nToken>=2
     && blob_eq(&xfer.aToken[0], "igot")
     && blob_is_hname(&xfer.aToken[1])
    ){
      if( isPush ){
        int rid = 0;
        int isPriv = 0;
        if( xfer.nToken==2 || blob_eq(&xfer.aToken[2],"1")==0 ){
          /* Client says the artifact is public */
          rid = rid_from_uuid(&xfer.aToken[1], 1, 0);
        }else if( g.perm.Private ){
          /* Client says the artifact is private and the client has
          ** permission to push private content.  Create a new phantom
          ** artifact that is marked private. */
          rid = rid_from_uuid(&xfer.aToken[1], 1, 1);
          isPriv = 1;
        }else{
          /* Client says the artifact is private and the client is unable
          ** or unwilling to send us the artifact.  If we already hold the
          ** artifact here on the server as a phantom, make sure that
          ** phantom is marked as private so that we don't keep asking about
          ** it in subsequent sync requests. */
          rid = rid_from_uuid(&xfer.aToken[1], 0, 1);
          isPriv = 1;
        }
        if( rid ){
          remote_has(rid);
          if( isPriv ){
            content_make_private(rid);
          }else{
            content_make_public(rid);
          }
        }
      }
    }else


    /*    pull  SERVERCODE  PROJECTCODE
    **    push  SERVERCODE  PROJECTCODE
1386
1387
1388
1389
1390
1391
1392

1393
1394
1395
1396
1397
1398
1399
1400
        deltaFlag = 1;
      }
      @ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x"))
    }else

    /*    login  USER  NONCE  SIGNATURE
    **

    ** Check for a valid login.  This has to happen before anything else.
    ** The client can send multiple logins.  Permissions are cumulative.
    */
    if( blob_eq(&xfer.aToken[0], "login")
     && xfer.nToken==4
    ){
      if( disableLogin ){
        g.perm.Read = g.perm.Write = g.perm.Private = g.perm.Admin = 1;







>
|







1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
        deltaFlag = 1;
      }
      @ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x"))
    }else

    /*    login  USER  NONCE  SIGNATURE
    **
    ** The client has sent login credentials to the server.
    ** Validate the login.  This has to happen before anything else.
    ** The client can send multiple logins.  Permissions are cumulative.
    */
    if( blob_eq(&xfer.aToken[0], "login")
     && xfer.nToken==4
    ){
      if( disableLogin ){
        g.perm.Read = g.perm.Write = g.perm.Private = g.perm.Admin = 1;
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
          break;
        }
      }
    }else

    /*    reqconfig  NAME
    **
    ** Request a configuration value
    */
    if( blob_eq(&xfer.aToken[0], "reqconfig")
     && xfer.nToken==2
    ){
      if( g.perm.Read ){
        char *zName = blob_str(&xfer.aToken[1]);
        if( zName[0]=='/' ){
          /* New style configuration transfer */
          int groupMask = configure_name_to_mask(&zName[1], 0);
          if( !g.perm.Admin ) groupMask &= ~(CONFIGSET_USER|CONFIGSET_SCRIBER);
          if( !g.perm.RdAddr ) groupMask &= ~CONFIGSET_ADDR;
          configure_send_group(xfer.pOut, groupMask, 0);
        }
      }
    }else

    /*   config NAME SIZE \n CONTENT
    **
    ** Receive a configuration value from the client.  This is only
    ** permitted for high-privilege users.
    */
    if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
        && blob_is_int(&xfer.aToken[2], &size) ){
      const char *zName = blob_str(&xfer.aToken[1]);
      Blob content;
      blob_zero(&content);
      blob_extract(xfer.pIn, size, &content);







|


















|
|







1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
          break;
        }
      }
    }else

    /*    reqconfig  NAME
    **
    ** Client is requesting a configuration value from the server
    */
    if( blob_eq(&xfer.aToken[0], "reqconfig")
     && xfer.nToken==2
    ){
      if( g.perm.Read ){
        char *zName = blob_str(&xfer.aToken[1]);
        if( zName[0]=='/' ){
          /* New style configuration transfer */
          int groupMask = configure_name_to_mask(&zName[1], 0);
          if( !g.perm.Admin ) groupMask &= ~(CONFIGSET_USER|CONFIGSET_SCRIBER);
          if( !g.perm.RdAddr ) groupMask &= ~CONFIGSET_ADDR;
          configure_send_group(xfer.pOut, groupMask, 0);
        }
      }
    }else

    /*   config NAME SIZE \n CONTENT
    **
    ** Client has sent a configuration value to the server.
    ** This is only permitted for high-privilege users.
    */
    if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
        && blob_is_int(&xfer.aToken[2], &size) ){
      const char *zName = blob_str(&xfer.aToken[1]);
      Blob content;
      blob_zero(&content);
      blob_extract(xfer.pIn, size, &content);
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499


1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516


1517
1518
1519
1520
1521
1522
1523
1524


1525
1526
1527






1528
1529
1530
1531
1532
1533
1534
    if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
      /* Process the cookie */
    }else


    /*    private
    **
    ** This card indicates that the next "file" or "cfile" will contain
    ** private content.
    */
    if( blob_eq(&xfer.aToken[0], "private") ){
      if( !g.perm.Private ){
        server_private_xfer_not_authorized();
      }else{
        xfer.nextIsPrivate = 1;
      }
    }else


    /*    pragma NAME VALUE...
    **
    ** The client issue pragmas to try to influence the behavior of the
    ** server.  These are requests only.  Unknown pragmas are silently
    ** ignored.
    */
    if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){

      /*   pragma send-private


      **
      ** If the user has the "x" privilege (which must be set explicitly -
      ** it is not automatic with "a" or "s") then this pragma causes
      ** private information to be pulled in addition to public records.
      */
      if( blob_eq(&xfer.aToken[1], "send-private") ){
        login_check_credentials();
        if( !g.perm.Private ){
          server_private_xfer_not_authorized();
        }else{
          xfer.syncPrivate = 1;
        }
      }

      /*   pragma send-catalog
      **
      ** Send igot cards for all known artifacts.


      */
      if( blob_eq(&xfer.aToken[1], "send-catalog") ){
        xfer.resync = 0x7fffffff;
      }

      /*   pragma client-version VERSION
      **
      ** Let the server know what version of Fossil is running on the client.


      */
      if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
        xfer.clientVersion = atoi(blob_str(&xfer.aToken[2]));






      }

      /*   pragma uv-hash HASH
      **
      ** The client wants to make sure that unversioned files are all synced.
      ** If the HASH does not match, send a complete catalog of
      ** "uvigot" cards.







|




















>
>
















|
>
>





|

|
>
>


|
>
>
>
>
>
>







1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
    if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
      /* Process the cookie */
    }else


    /*    private
    **
    ** The client card indicates that the next "file" or "cfile" will contain
    ** private content.
    */
    if( blob_eq(&xfer.aToken[0], "private") ){
      if( !g.perm.Private ){
        server_private_xfer_not_authorized();
      }else{
        xfer.nextIsPrivate = 1;
      }
    }else


    /*    pragma NAME VALUE...
    **
    ** The client issue pragmas to try to influence the behavior of the
    ** server.  These are requests only.  Unknown pragmas are silently
    ** ignored.
    */
    if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){

      /*   pragma send-private
      **
      ** The client is requesting private artifacts.
      **
      ** If the user has the "x" privilege (which must be set explicitly -
      ** it is not automatic with "a" or "s") then this pragma causes
      ** private information to be pulled in addition to public records.
      */
      if( blob_eq(&xfer.aToken[1], "send-private") ){
        login_check_credentials();
        if( !g.perm.Private ){
          server_private_xfer_not_authorized();
        }else{
          xfer.syncPrivate = 1;
        }
      }

      /*   pragma send-catalog
      **
      ** The client wants to see igot cards for all known artifacts.
      ** This is used as part of "sync --verily" to help ensure that
      ** no artifacts have been missed on prior syncs.
      */
      if( blob_eq(&xfer.aToken[1], "send-catalog") ){
        xfer.resync = 0x7fffffff;
      }

      /*   pragma client-version VERSION ?DATE? ?TIME?
      **
      ** The client announces to the server what version of Fossil it
      ** is running.  The DATE and TIME are a pure numeric ISO8601 time
      ** for the specific check-in of the client.
      */
      if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
        xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
        if( xfer.nToken>=5 ){
          xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
          xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
          @ pragma server-version %d(RELEASE_VERSION_NUMBER) \
          @ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
        }
      }

      /*   pragma uv-hash HASH
      **
      ** The client wants to make sure that unversioned files are all synced.
      ** If the HASH does not match, send a complete catalog of
      ** "uvigot" cards.
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
        uvCatalogSent = 1;
      }

      /*   pragma ci-lock CHECKIN-HASH CLIENT-ID
      **
      ** The client wants to make non-branch commit against the check-in
      ** identified by CHECKIN-HASH.  The server will remember this and
      ** subsequent ci-lock request from different clients will generate
      ** a ci-lock-fail pragma in the reply.
      */
      if( blob_eq(&xfer.aToken[1], "ci-lock")
       && xfer.nToken==4
       && blob_is_hname(&xfer.aToken[2])
      ){
        Stmt q;







|







1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
        uvCatalogSent = 1;
      }

      /*   pragma ci-lock CHECKIN-HASH CLIENT-ID
      **
      ** The client wants to make non-branch commit against the check-in
      ** identified by CHECKIN-HASH.  The server will remember this and
      ** subsequent ci-lock requests from different clients will generate
      ** a ci-lock-fail pragma in the reply.
      */
      if( blob_eq(&xfer.aToken[1], "ci-lock")
       && xfer.nToken==4
       && blob_is_hname(&xfer.aToken[2])
      ){
        Stmt q;
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753

1754
1755
1756
1757
1758
1759
1760
** routine is called by the client.
**
** Records are pushed to the server if pushFlag is true.  Records
** are pulled if pullFlag is true.  A full sync occurs if both are
** true.
*/
int client_sync(
  unsigned syncFlags,     /* Mask of SYNC_* flags */
  unsigned configRcvMask, /* Receive these configuration items */
  unsigned configSendMask /* Send these configuration items */

){
  int go = 1;             /* Loop until zero */
  int nCardSent = 0;      /* Number of cards sent */
  int nCardRcvd = 0;      /* Number of cards received */
  int nCycle = 0;         /* Number of round trips to the server */
  int size;               /* Size of a config value or uvfile */
  int origConfigRcvMask;  /* Original value of configRcvMask */







|
|
|
>







1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
** routine is called by the client.
**
** Records are pushed to the server if pushFlag is true.  Records
** are pulled if pullFlag is true.  A full sync occurs if both are
** true.
*/
int client_sync(
  unsigned syncFlags,      /* Mask of SYNC_* flags */
  unsigned configRcvMask,  /* Receive these configuration items */
  unsigned configSendMask, /* Send these configuration items */
  const char *zAltPCode    /* Alternative project code (usually NULL) */
){
  int go = 1;             /* Loop until zero */
  int nCardSent = 0;      /* Number of cards sent */
  int nCardRcvd = 0;      /* Number of cards received */
  int nCycle = 0;         /* Number of round trips to the server */
  int size;               /* Size of a config value or uvfile */
  int origConfigRcvMask;  /* Original value of configRcvMask */
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
  transport_stats(0, 0, 1);
  socket_global_init();
  memset(&xfer, 0, sizeof(xfer));
  xfer.pIn = &recv;
  xfer.pOut = &send;
  xfer.mxSend = db_get_int("max-upload", 250000);
  xfer.maxTime = -1;
  xfer.clientVersion = RELEASE_VERSION_NUMBER;
  if( syncFlags & SYNC_PRIVATE ){
    g.perm.Private = 1;
    xfer.syncPrivate = 1;
  }

  blobarray_zero(xfer.aToken, count(xfer.aToken));
  blob_zero(&send);







|







1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
  transport_stats(0, 0, 1);
  socket_global_init();
  memset(&xfer, 0, sizeof(xfer));
  xfer.pIn = &recv;
  xfer.pOut = &send;
  xfer.mxSend = db_get_int("max-upload", 250000);
  xfer.maxTime = -1;
  xfer.remoteVersion = RELEASE_VERSION_NUMBER;
  if( syncFlags & SYNC_PRIVATE ){
    g.perm.Private = 1;
    xfer.syncPrivate = 1;
  }

  blobarray_zero(xfer.aToken, count(xfer.aToken));
  blob_zero(&send);
1853
1854
1855
1856
1857
1858
1859
1860

1861
1862


1863
1864
1865
1866
1867
1868
1869
1870
1871

1872
1873
1874
1875
1876
1877
1878
       ") WITHOUT ROWID;"
       "INSERT INTO uv_toSend(name,mtimeOnly)"
       "  SELECT name, 0 FROM unversioned WHERE hash IS NOT NULL;"
    );
  }

  /*
  ** Always begin with a clone, pull, or push message

  */
  blob_appendf(&send, "pragma client-version %d\n", RELEASE_VERSION_NUMBER);


  if( syncFlags & SYNC_CLONE ){
    blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
    syncFlags &= ~(SYNC_PUSH|SYNC_PULL);
    nCardSent++;
    /* TBD: Request all transferable configuration values */
    content_enable_dephantomize(0);
    zOpType = "Clone";
  }else if( syncFlags & SYNC_PULL ){
    blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);

    nCardSent++;
    zOpType = (syncFlags & SYNC_PUSH)?"Sync":"Pull";
    if( (syncFlags & SYNC_RESYNC)!=0 && nCycle<2 ){
      blob_appendf(&send, "pragma send-catalog\n");
      nCardSent++;
    }
  }







|
>

|
>
>








|
>







1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
       ") WITHOUT ROWID;"
       "INSERT INTO uv_toSend(name,mtimeOnly)"
       "  SELECT name, 0 FROM unversioned WHERE hash IS NOT NULL;"
    );
  }

  /*
  ** The request from the client always begin with a clone, pull,
  ** or push message.
  */
  blob_appendf(&send, "pragma client-version %d %d %d\n",
               RELEASE_VERSION_NUMBER, MANIFEST_NUMERIC_DATE,
               MANIFEST_NUMERIC_TIME);
  if( syncFlags & SYNC_CLONE ){
    blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
    syncFlags &= ~(SYNC_PUSH|SYNC_PULL);
    nCardSent++;
    /* TBD: Request all transferable configuration values */
    content_enable_dephantomize(0);
    zOpType = "Clone";
  }else if( syncFlags & SYNC_PULL ){
    blob_appendf(&send, "pull %s %s\n", zSCode,
                 zAltPCode ? zAltPCode : zPCode);
    nCardSent++;
    zOpType = (syncFlags & SYNC_PUSH)?"Sync":"Pull";
    if( (syncFlags & SYNC_RESYNC)!=0 && nCycle<2 ){
      blob_appendf(&send, "pragma send-catalog\n");
      nCardSent++;
    }
  }
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953

1954
1955
1956
1957
1958
1959
1960
    db_record_repository_filename(0);
    db_multi_exec(
      "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
    );
    manifest_crosslink_begin();


    /* Send back the most recently received cookie.  Let the server
    ** figure out if this is a cookie that it cares about.
    */
    zCookie = db_get("cookie", 0);
    if( zCookie ){
      blob_appendf(&send, "cookie %s\n", zCookie);
    }

    /* Generate gimme cards for phantoms and leaf cards
    ** for all leaves.
    */
    if( (syncFlags & SYNC_PULL)!=0
     || ((syncFlags & SYNC_CLONE)!=0 && cloneSeqno==1)
    ){
      request_phantoms(&xfer, mxPhantomReq);
    }
    if( syncFlags & SYNC_PUSH ){
      send_unsent(&xfer);
      nCardSent += send_unclustered(&xfer);
      if( syncFlags & SYNC_PRIVATE ) send_private(&xfer);
    }

    /* Send configuration parameter requests.  On a clone, delay sending
    ** this until the second cycle since the login card might fail on
    ** the first cycle.
    */
    if( configRcvMask && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
      const char *zName;
      if( zOpType==0 ) zOpType = "Pull";
      zName = configure_first_name(configRcvMask);
      while( zName ){
        blob_appendf(&send, "reqconfig %s\n", zName);
        zName = configure_next_name(configRcvMask);
        nCardSent++;
      }
      origConfigRcvMask = configRcvMask;
      configRcvMask = 0;
    }

    /* Send a request to sync unversioned files.  On a clone, delay sending
    ** this until the second cycle since the login card might fail on
    ** the first cycle.
    */
    if( (syncFlags & SYNC_UNVERSIONED)!=0
     && ((syncFlags & SYNC_CLONE)==0 || nCycle>0)
     && !uvHashSent
    ){
      blob_appendf(&send, "pragma uv-hash %s\n", unversioned_content_hash(0));
      nCardSent++;
      uvHashSent = 1;
    }

    /* Send configuration parameters being pushed */

    if( configSendMask ){
      if( zOpType==0 ) zOpType = "Push";
      nCardSent += configure_send_group(xfer.pOut, configSendMask, 0);
      configSendMask = 0;
    }

    /* Send unversioned files present here on the client but missing or







|
|






|
<












|
















|
|
|










|
>







1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981

1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
    db_record_repository_filename(0);
    db_multi_exec(
      "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
    );
    manifest_crosslink_begin();


    /* Client sends the most recently received cookie back to the server.
    ** Let the server figure out if this is a cookie that it cares about.
    */
    zCookie = db_get("cookie", 0);
    if( zCookie ){
      blob_appendf(&send, "cookie %s\n", zCookie);
    }

    /* Client sends gimme cards for phantoms

    */
    if( (syncFlags & SYNC_PULL)!=0
     || ((syncFlags & SYNC_CLONE)!=0 && cloneSeqno==1)
    ){
      request_phantoms(&xfer, mxPhantomReq);
    }
    if( syncFlags & SYNC_PUSH ){
      send_unsent(&xfer);
      nCardSent += send_unclustered(&xfer);
      if( syncFlags & SYNC_PRIVATE ) send_private(&xfer);
    }

    /* Client sends configuration parameter requests.  On a clone, delay sending
    ** this until the second cycle since the login card might fail on
    ** the first cycle.
    */
    if( configRcvMask && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
      const char *zName;
      if( zOpType==0 ) zOpType = "Pull";
      zName = configure_first_name(configRcvMask);
      while( zName ){
        blob_appendf(&send, "reqconfig %s\n", zName);
        zName = configure_next_name(configRcvMask);
        nCardSent++;
      }
      origConfigRcvMask = configRcvMask;
      configRcvMask = 0;
    }

    /* Client sends a request to sync unversioned files.
    ** On a clone, delay sending this until the second cycle since
    ** the login card might fail on the first cycle.
    */
    if( (syncFlags & SYNC_UNVERSIONED)!=0
     && ((syncFlags & SYNC_CLONE)==0 || nCycle>0)
     && !uvHashSent
    ){
      blob_appendf(&send, "pragma uv-hash %s\n", unversioned_content_hash(0));
      nCardSent++;
      uvHashSent = 1;
    }

    /* On a "fossil config push", the client send configuration parameters
    ** being pushed up to the server */
    if( configSendMask ){
      if( zOpType==0 ) zOpType = "Push";
      nCardSent += configure_send_group(xfer.pOut, configSendMask, 0);
      configSendMask = 0;
    }

    /* Send unversioned files present here on the client but missing or
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
      }
      blob_appendf(&send, "pragma ci-lock %s %s\n", zCkinLock, zClientId);
      zCkinLock = 0;
    }else if( zClientId ){
      blob_appendf(&send, "pragma ci-unlock %s\n", zClientId);
    }

    /* Append randomness to the end of the message.  This makes all
    ** messages unique so that that the login-card nonce will always
    ** be unique.
    */
    zRandomness = db_text(0, "SELECT hex(randomblob(20))");
    blob_appendf(&send, "# %s\n", zRandomness);
    free(zRandomness);








|







2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
      }
      blob_appendf(&send, "pragma ci-lock %s %s\n", zCkinLock, zClientId);
      zCkinLock = 0;
    }else if( zClientId ){
      blob_appendf(&send, "pragma ci-unlock %s\n", zClientId);
    }

    /* Append randomness to the end of the uplink message.  This makes all
    ** messages unique so that that the login-card nonce will always
    ** be unique.
    */
    zRandomness = db_text(0, "SELECT hex(randomblob(20))");
    blob_appendf(&send, "# %s\n", zRandomness);
    free(zRandomness);

2048
2049
2050
2051
2052
2053
2054

2055
2056
2057
2058


2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070

2071
2072
2073
2074
2075
2076
2077
    }
    nCardSent = 0;
    nCardRcvd = 0;
    xfer.nFileSent = 0;
    xfer.nDeltaSent = 0;
    xfer.nGimmeSent = 0;
    xfer.nIGotSent = 0;


    lastPctDone = -1;
    blob_reset(&send);
    blob_appendf(&send, "pragma client-version %d\n", RELEASE_VERSION_NUMBER);


    rArrivalTime = db_double(0.0, "SELECT julianday('now')");

    /* Send the send-private pragma if we are trying to sync private data */
    if( syncFlags & SYNC_PRIVATE ){
      blob_append(&send, "pragma send-private\n", -1);
    }

    /* Begin constructing the next message (which might never be
    ** sent) by beginning with the pull or push cards
    */
    if( syncFlags & SYNC_PULL ){
      blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);

      nCardSent++;
    }
    if( syncFlags & SYNC_PUSH ){
      blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
      nCardSent++;
    }
    go = 0;







>



|
>
>











|
>







2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
    }
    nCardSent = 0;
    nCardRcvd = 0;
    xfer.nFileSent = 0;
    xfer.nDeltaSent = 0;
    xfer.nGimmeSent = 0;
    xfer.nIGotSent = 0;
    xfer.nPrivIGot = 0;

    lastPctDone = -1;
    blob_reset(&send);
    blob_appendf(&send, "pragma client-version %d %d %d\n",
                 RELEASE_VERSION_NUMBER, MANIFEST_NUMERIC_DATE,
                 MANIFEST_NUMERIC_TIME);
    rArrivalTime = db_double(0.0, "SELECT julianday('now')");

    /* Send the send-private pragma if we are trying to sync private data */
    if( syncFlags & SYNC_PRIVATE ){
      blob_append(&send, "pragma send-private\n", -1);
    }

    /* Begin constructing the next message (which might never be
    ** sent) by beginning with the pull or push cards
    */
    if( syncFlags & SYNC_PULL ){
      blob_appendf(&send, "pull %s %s\n", zSCode,
                   zAltPCode ? zAltPCode : zPCode);
      nCardSent++;
    }
    if( syncFlags & SYNC_PUSH ){
      blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
      nCardSent++;
    }
    go = 0;
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146

2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
          fflush(stdout);
        }
      }

      /*   file HASH SIZE \n CONTENT
      **   file HASH DELTASRC SIZE \n CONTENT
      **
      ** Receive a file transmitted from the server.
      */
      if( blob_eq(&xfer.aToken[0],"file") ){
        xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0, 0, 0);
        nArtifactRcvd++;
      }else

      /*   cfile HASH USIZE CSIZE \n CONTENT
      **   cfile HASH DELTASRC USIZE CSIZE \n CONTENT
      **
      ** Receive a compressed file transmitted from the server.
      */
      if( blob_eq(&xfer.aToken[0],"cfile") ){
        xfer_accept_compressed_file(&xfer, 0, 0);
        nArtifactRcvd++;
      }else

      /*   uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
      **
      ** Accept an unversioned file from the server.
      */
      if( blob_eq(&xfer.aToken[0], "uvfile") ){
        xfer_accept_unversioned_file(&xfer, 1);
        nArtifactRcvd++;
        nUvFileRcvd++;
        if( syncFlags & SYNC_VERBOSE ){
          fossil_print("\rUnversioned-file received: %s\n",
                       blob_str(&xfer.aToken[1]));
        }
      }else

      /*   gimme HASH
      **

      ** Server is requesting a file.  If the file is a manifest, assume
      ** that the server will also want to know all of the content files
      ** associated with the manifest and send those too.
      */
      if( blob_eq(&xfer.aToken[0], "gimme")
       && xfer.nToken==2
       && blob_is_hname(&xfer.aToken[1])
      ){
        if( syncFlags & SYNC_PUSH ){
          int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);







|









|








|













>
|
|
|







2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
          fflush(stdout);
        }
      }

      /*   file HASH SIZE \n CONTENT
      **   file HASH DELTASRC SIZE \n CONTENT
      **
      ** Client receives a file transmitted from the server.
      */
      if( blob_eq(&xfer.aToken[0],"file") ){
        xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0, 0, 0);
        nArtifactRcvd++;
      }else

      /*   cfile HASH USIZE CSIZE \n CONTENT
      **   cfile HASH DELTASRC USIZE CSIZE \n CONTENT
      **
      ** Client receives a compressed file transmitted from the server.
      */
      if( blob_eq(&xfer.aToken[0],"cfile") ){
        xfer_accept_compressed_file(&xfer, 0, 0);
        nArtifactRcvd++;
      }else

      /*   uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
      **
      ** Client accepts an unversioned file from the server.
      */
      if( blob_eq(&xfer.aToken[0], "uvfile") ){
        xfer_accept_unversioned_file(&xfer, 1);
        nArtifactRcvd++;
        nUvFileRcvd++;
        if( syncFlags & SYNC_VERBOSE ){
          fossil_print("\rUnversioned-file received: %s\n",
                       blob_str(&xfer.aToken[1]));
        }
      }else

      /*   gimme HASH
      **
      ** Client receives an artifact request from the server.
      ** If the file is a manifest, assume that the server will also want
      ** to know all of the content artifacts associated with the manifest
      ** and send those too.
      */
      if( blob_eq(&xfer.aToken[0], "gimme")
       && xfer.nToken==2
       && blob_is_hname(&xfer.aToken[1])
      ){
        if( syncFlags & SYNC_PUSH ){
          int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
2174
2175
2176
2177
2178
2179
2180



2181

2182
2183
2184
2185
2186
2187
2188
       && blob_eq(&xfer.aToken[0], "igot")
       && blob_is_hname(&xfer.aToken[1])
      ){
        int rid;
        int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1");
        rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
        if( rid>0 ){



          if( !isPriv ) content_make_public(rid);

        }else if( isPriv && !g.perm.Private ){
          /* ignore private files */
        }else if( (syncFlags & (SYNC_PULL|SYNC_CLONE))!=0 ){
          rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
          if( rid ) newPhantom = 1;
        }
        remote_has(rid);







>
>
>
|
>







2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
       && blob_eq(&xfer.aToken[0], "igot")
       && blob_is_hname(&xfer.aToken[1])
      ){
        int rid;
        int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1");
        rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
        if( rid>0 ){
          if( isPriv ){
            content_make_private(rid);
          }else{
            content_make_public(rid);
          }
        }else if( isPriv && !g.perm.Private ){
          /* ignore private files */
        }else if( (syncFlags & (SYNC_PULL|SYNC_CLONE))!=0 ){
          rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
          if( rid ) newPhantom = 1;
        }
        remote_has(rid);
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
                        zName);
        }
      }else

      /*   push  SERVERCODE  PRODUCTCODE
      **
      ** Should only happen in response to a clone.  This message tells
      ** the client what product to use for the new database.
      */
      if( blob_eq(&xfer.aToken[0],"push")
       && xfer.nToken==3
       && (syncFlags & SYNC_CLONE)!=0
       && blob_is_hname(&xfer.aToken[2])
      ){
        if( zPCode==0 ){
          zPCode = mprintf("%b", &xfer.aToken[2]);
          db_set("project-code", zPCode, 0);
        }
        if( cloneSeqno>0 ) blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
        nCardSent++;
      }else

      /*   config NAME SIZE \n CONTENT
      **
      ** Receive a configuration value from the server.
      **
      ** The received configuration setting is silently ignored if it was
      ** not requested by a prior "reqconfig" sent from client to server.
      */
      if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
          && blob_is_int(&xfer.aToken[2], &size) ){
        const char *zName = blob_str(&xfer.aToken[1]);







|
















|







2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
                        zName);
        }
      }else

      /*   push  SERVERCODE  PRODUCTCODE
      **
      ** Should only happen in response to a clone.  This message tells
      ** the client what product code to use for the new database.
      */
      if( blob_eq(&xfer.aToken[0],"push")
       && xfer.nToken==3
       && (syncFlags & SYNC_CLONE)!=0
       && blob_is_hname(&xfer.aToken[2])
      ){
        if( zPCode==0 ){
          zPCode = mprintf("%b", &xfer.aToken[2]);
          db_set("project-code", zPCode, 0);
        }
        if( cloneSeqno>0 ) blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
        nCardSent++;
      }else

      /*   config NAME SIZE \n CONTENT
      **
      ** Client receive a configuration value from the server.
      **
      ** The received configuration setting is silently ignored if it was
      ** not requested by a prior "reqconfig" sent from client to server.
      */
      if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
          && blob_is_int(&xfer.aToken[2], &size) ){
        const char *zName = blob_str(&xfer.aToken[1]);
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339

2340
2341
2342
2343
2344
2345
2346
2347
        blob_reset(&content);
        blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
      }else


      /*    cookie TEXT
      **
      ** The server might include a cookie in its reply.  The client
      ** should remember this cookie and send it back to the server
      ** in its next query.
      **
      ** Each cookie received overwrites the prior cookie from the
      ** same server.
      */
      if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
        db_set("cookie", blob_str(&xfer.aToken[1]), 0);
      }else


      /*    private
      **
      ** This card indicates that the next "file" or "cfile" will contain
      ** private content.
      */
      if( blob_eq(&xfer.aToken[0], "private") ){
        xfer.nextIsPrivate = 1;
      }else


      /*    clone_seqno N
      **
      ** When doing a clone, the server tries to send all of its artifacts
      ** in sequence.  This card indicates the sequence number of the next
      ** blob that needs to be sent.  If N<=0 that indicates that all blobs
      ** have been sent.
      */
      if( blob_eq(&xfer.aToken[0], "clone_seqno") && xfer.nToken==2 ){
        blob_is_int(&xfer.aToken[1], &cloneSeqno);
      }else

      /*   message MESSAGE
      **

      ** Print a message.  Similar to "error" but does not stop processing.
      **
      ** If the "login failed" message is seen, clear the sync password prior
      ** to the next cycle.
      */
      if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
        char *zMsg = blob_terminate(&xfer.aToken[1]);
        defossilize(zMsg);







|













|
|



















>
|







2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
        blob_reset(&content);
        blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
      }else


      /*    cookie TEXT
      **
      ** The client reserves a cookie from the server.  The client
      ** should remember this cookie and send it back to the server
      ** in its next query.
      **
      ** Each cookie received overwrites the prior cookie from the
      ** same server.
      */
      if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
        db_set("cookie", blob_str(&xfer.aToken[1]), 0);
      }else


      /*    private
      **
      ** The server tells the client that the next "file" or "cfile" will
      ** contain private content.
      */
      if( blob_eq(&xfer.aToken[0], "private") ){
        xfer.nextIsPrivate = 1;
      }else


      /*    clone_seqno N
      **
      ** When doing a clone, the server tries to send all of its artifacts
      ** in sequence.  This card indicates the sequence number of the next
      ** blob that needs to be sent.  If N<=0 that indicates that all blobs
      ** have been sent.
      */
      if( blob_eq(&xfer.aToken[0], "clone_seqno") && xfer.nToken==2 ){
        blob_is_int(&xfer.aToken[1], &cloneSeqno);
      }else

      /*   message MESSAGE
      **
      ** A message is received from the server.  Print it.
      ** Similar to "error" but does not stop processing.
      **
      ** If the "login failed" message is seen, clear the sync password prior
      ** to the next cycle.
      */
      if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
        char *zMsg = blob_terminate(&xfer.aToken[1]);
        defossilize(zMsg);
2359
2360
2361
2362
2363
2364
2365
















2366
2367
2368
2369
2370
2371
2372





2373
2374
2375
2376
2377
2378
2379
      /*    pragma NAME VALUE...
      **
      ** The server can send pragmas to try to convey meta-information to
      ** the client.  These are informational only.  Unknown pragmas are
      ** silently ignored.
      */
      if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){
















        /* If the server is unwill to accept new unversioned content (because
        ** this client lacks the necessary permissions) then it sends a
        ** "uv-pull-only" pragma so that the client will know not to waste
        ** bandwidth trying to upload unversioned content.  If the server
        ** does accept new unversioned content, it sends "uv-push-ok".
        */
        if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){





          if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1;
        }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
          uvDoPush = 1;
        }

        /*    pragma ci-lock-fail  USER-HOLDING-LOCK  LOCK-TIME
        **







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






>
>
>
>
>







2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
      /*    pragma NAME VALUE...
      **
      ** The server can send pragmas to try to convey meta-information to
      ** the client.  These are informational only.  Unknown pragmas are
      ** silently ignored.
      */
      if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){
        /*   pragma server-version VERSION ?DATE? ?TIME?
        **
        ** The servger announces to the server what version of Fossil it
        ** is running.  The DATE and TIME are a pure numeric ISO8601 time
        ** for the specific check-in of the client.
        */
        if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
          xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
          if( xfer.nToken>=5 ){
            xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
            xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
          }
        }

        /*   pragma uv-pull-only
        **
        ** If the server is unwill to accept new unversioned content (because
        ** this client lacks the necessary permissions) then it sends a
        ** "uv-pull-only" pragma so that the client will know not to waste
        ** bandwidth trying to upload unversioned content.  If the server
        ** does accept new unversioned content, it sends "uv-push-ok".
        */
        if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
          fossil_print(
            "Warning: uv-pull-only                                       \n"
            "         Unable to push unversioned content because you lack\n"
            "         sufficient permission on the server\n"
          );
          if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1;
        }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
          uvDoPush = 1;
        }

        /*    pragma ci-lock-fail  USER-HOLDING-LOCK  LOCK-TIME
        **
2397
2398
2399
2400
2401
2402
2403

2404
2405
2406
2407
2408
2409
2410
2411
          }
          g.ckinLockFail = fossil_strdup(zUser);
        }
      }else

      /*   error MESSAGE
      **

      ** Report an error and abandon the sync session.
      **
      ** Except, when cloning we will sometimes get an error on the
      ** first message exchange because the project-code is unknown
      ** and so the login card on the request was invalid.  The project-code
      ** is returned in the reply before the error card, so second and
      ** subsequent messages should be OK.  Nevertheless, we need to ignore
      ** the error card on the first message of a clone.







>
|







2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
          }
          g.ckinLockFail = fossil_strdup(zUser);
        }
      }else

      /*   error MESSAGE
      **
      ** The server is reporting an error.  The client will abandon
      ** the sync session.
      **
      ** Except, when cloning we will sometimes get an error on the
      ** first message exchange because the project-code is unknown
      ** and so the login card on the request was invalid.  The project-code
      ** is returned in the reply before the error card, so second and
      ** subsequent messages should be OK.  Nevertheless, we need to ignore
      ** the error card on the first message of a clone.
2481
2482
2483
2484
2485
2486
2487

2488
2489
2490
2491
2492
2493
2494

    /* If we have one or more files queued to send, then go
    ** another round
    */
    if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
      go = 1;
    }


    /* If this is a clone, the go at least two rounds */
    if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;

    /* Stop the cycle if the server sends a "clone_seqno 0" card and
    ** we have gone at least two rounds.  Always go at least two rounds
    ** on a clone in order to be sure to retrieve the configuration







>







2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599

    /* If we have one or more files queued to send, then go
    ** another round
    */
    if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
      go = 1;
    }
    if( xfer.nPrivIGot>0 && nCycle==1 ) go = 1;

    /* If this is a clone, the go at least two rounds */
    if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;

    /* Stop the cycle if the server sends a "clone_seqno 0" card and
    ** we have gone at least two rounds.  Always go at least two rounds
    ** on a clone in order to be sure to retrieve the configuration
Changes to src/xfersetup.c.
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    @ <input type="submit" name="sync" value="%h(zButton)" />
    @ </div></form>
    @
    if( P("sync") ){
      user_select();
      url_enable_proxy(0);
      @ <pre class="xfersetup">
      client_sync(syncFlags, 0, 0);
      @ </pre>
    }
  }

  style_footer();
}








|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    @ <input type="submit" name="sync" value="%h(zButton)" />
    @ </div></form>
    @
    if( P("sync") ){
      user_select();
      url_enable_proxy(0);
      @ <pre class="xfersetup">
      client_sync(syncFlags, 0, 0, 0);
      @ </pre>
    }
  }

  style_footer();
}

Added test/csp1.html.




































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<head>
<title>Title: Content Security Policy Test</title>
</head>
<body>
<h1>Content Security Policy Test</h1>

<p>If the content-security-policy is ineffective, a pop-up dialog
box will appears.  If there is no dialog box, then CSP is working
correctly.</p>

<script>alert('Content Security Policy is ineffective');</script>
<img src='/' onerror='alert("CSP is ineffective")'>

<p>As a double-check, open the Developer Console in your web-browser
and verify that two CSP violations were detected and blocked.</p>
</body>
Changes to test/th1.test.
1039
1040
1041
1042
1043
1044
1045
1046

1047
1048
1049
1050
1051
1052
1053
set base_commands {anoncap anycap array artifact break breakpoint catch\
      cgiHeaderLine checkout combobox continue date decorate dir enable_output \
      encode64 error expr for getParameter glob_match globalState hascap \
      hasfeature html htmlize http httpize if info insertCsrf lindex linecount \
      list llength lsearch markdown nonce proc puts query randhex redirect\
      regexp reinitialize rename render repository return searchable set\
      setParameter setting stime string styleFooter styleHeader styleScript\
      tclReady trace unset unversioned uplevel upvar utime verifyCsrf wiki}

set tcl_commands {tclEval tclExpr tclInvoke tclIsSafe tclMakeSafe}
if {$th1Tcl} {
  test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands $tcl_commands"]}
} else {
  test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands"]}
}








|
>







1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
set base_commands {anoncap anycap array artifact break breakpoint catch\
      cgiHeaderLine checkout combobox continue date decorate dir enable_output \
      encode64 error expr for getParameter glob_match globalState hascap \
      hasfeature html htmlize http httpize if info insertCsrf lindex linecount \
      list llength lsearch markdown nonce proc puts query randhex redirect\
      regexp reinitialize rename render repository return searchable set\
      setParameter setting stime string styleFooter styleHeader styleScript\
      tclReady trace unset unversioned uplevel upvar utime verifyCsrf\
      verifyLogin wiki}
set tcl_commands {tclEval tclExpr tclInvoke tclIsSafe tclMakeSafe}
if {$th1Tcl} {
  test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands $tcl_commands"]}
} else {
  test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands"]}
}

Changes to win/Makefile.PellesCGMake.
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
UTILS_OBJ=$(UTILS:.exe=.obj)
UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c))

# define the SQLite files, which need special flags on compile
SQLITESRC=sqlite3.c
ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf))
SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj))
SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_WIN32_NO_ANSI

# define the SQLite shell files, which need special flags on compile
SQLITESHELLSRC=shell.c
ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf))
SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj))
SQLITESHELLDEFINES=-DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen

# define the th scripting files, which need special flags on compile
THSRC=th.c th_lang.c
ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf))
THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj))

# define the zlib files, needed by this compile







|





|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
UTILS_OBJ=$(UTILS:.exe=.obj)
UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c))

# define the SQLite files, which need special flags on compile
SQLITESRC=sqlite3.c
ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf))
SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj))
SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DSQLITE_WIN32_NO_ANSI

# define the SQLite shell files, which need special flags on compile
SQLITESHELLSRC=shell.c
ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf))
SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj))
SQLITESHELLDEFINES=-DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen

# define the th scripting files, which need special flags on compile
THSRC=th.c th_lang.c
ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf))
THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj))

# define the zlib files, needed by this compile
Changes to win/Makefile.dmc.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
SSL    =

CFLAGS = -o
BCC    = $(DMDIR)\bin\dmc $(CFLAGS)
TCC    = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
LIBS   = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi

SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB

SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen

SRC   = add_.c alerts_.c allrepo_.c attach_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c

OBJ   = $(OBJDIR)\add$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O


RC=$(DMDIR)\bin\rcc
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__

APPNAME = $(OBJDIR)\fossil$(E)

all: $(APPNAME)

$(APPNAME) : translate$E mkindex$E codecheck1$E headers  $(OBJ) $(OBJDIR)\link
	cd $(OBJDIR)
	codecheck1$E $(SRC)
	$(DMDIR)\bin\link @link

$(OBJDIR)\fossil.res:	$B\win\fossil.rc
	$(RC) $(RCFLAGS) -o$@ $**

$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
	+echo add alerts allrepo attach backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file finfo foci forum fshell fusefs fuzz glob graph gzip hname http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
	+echo fossil >> $@
	+echo fossil >> $@
	+echo $(LIBS) >> $@
	+echo. >> $@
	+echo fossil >> $@

translate$E: $(SRCDIR)\translate.c







|

|

|

|


















|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
SSL    =

CFLAGS = -o
BCC    = $(DMDIR)\bin\dmc $(CFLAGS)
TCC    = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
LIBS   = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi

SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0

SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen

SRC   = add_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c

OBJ   = $(OBJDIR)\add$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O


RC=$(DMDIR)\bin\rcc
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__

APPNAME = $(OBJDIR)\fossil$(E)

all: $(APPNAME)

$(APPNAME) : translate$E mkindex$E codecheck1$E headers  $(OBJ) $(OBJDIR)\link
	cd $(OBJDIR)
	codecheck1$E $(SRC)
	$(DMDIR)\bin\link @link

$(OBJDIR)\fossil.res:	$B\win\fossil.rc
	$(RC) $(RCFLAGS) -o$@ $**

$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
	+echo add alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file finfo foci forum fshell fusefs fuzz glob graph gzip hname http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
	+echo fossil >> $@
	+echo fossil >> $@
	+echo $(LIBS) >> $@
	+echo. >> $@
	+echo fossil >> $@

translate$E: $(SRCDIR)\translate.c
150
151
152
153
154
155
156






157
158
159
160
161
162
163
	+translate$E $** > $@

$(OBJDIR)\attach$O : attach_.c attach.h
	$(TCC) -o$@ -c attach_.c

attach_.c : $(SRCDIR)\attach.c
	+translate$E $** > $@







$(OBJDIR)\backoffice$O : backoffice_.c backoffice.h
	$(TCC) -o$@ -c backoffice_.c

backoffice_.c : $(SRCDIR)\backoffice.c
	+translate$E $** > $@








>
>
>
>
>
>







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
	+translate$E $** > $@

$(OBJDIR)\attach$O : attach_.c attach.h
	$(TCC) -o$@ -c attach_.c

attach_.c : $(SRCDIR)\attach.c
	+translate$E $** > $@

$(OBJDIR)\backlink$O : backlink_.c backlink.h
	$(TCC) -o$@ -c backlink_.c

backlink_.c : $(SRCDIR)\backlink.c
	+translate$E $** > $@

$(OBJDIR)\backoffice$O : backoffice_.c backoffice.h
	$(TCC) -o$@ -c backoffice_.c

backoffice_.c : $(SRCDIR)\backoffice.c
	+translate$E $** > $@

962
963
964
965
966
967
968
969
970
$(OBJDIR)\zip$O : zip_.c zip.h
	$(TCC) -o$@ -c zip_.c

zip_.c : $(SRCDIR)\zip.c
	+translate$E $** > $@

headers: makeheaders$E page_index.h builtin_data.h default_css.h VERSION.h
	 +makeheaders$E add_.c:add.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
	@copy /Y nul: headers







|

968
969
970
971
972
973
974
975
976
$(OBJDIR)\zip$O : zip_.c zip.h
	$(TCC) -o$@ -c zip_.c

zip_.c : $(SRCDIR)\zip.c
	+translate$E $** > $@

headers: makeheaders$E page_index.h builtin_data.h default_css.h VERSION.h
	 +makeheaders$E add_.c:add.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
	@copy /Y nul: headers
Changes to win/Makefile.mingw.
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
endif

#### The directories where the OpenSSL include and library files are located.
#    The recommended usage here is to use the Sysinternals junction tool
#    to create a hard link between an "openssl-1.x" sub-directory of the
#    Fossil source code directory and the target OpenSSL source directory.
#
OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1d
OPENSSLINCDIR = $(OPENSSLDIR)/include
OPENSSLLIBDIR = $(OPENSSLDIR)

#### Either the directory where the Tcl library is installed or the Tcl
#    source code directory resides (depending on the value of the macro
#    FOSSIL_TCL_SOURCE).  If this points to the Tcl install directory,
#    this directory must have "include" and "lib" sub-directories.  If







|







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
endif

#### The directories where the OpenSSL include and library files are located.
#    The recommended usage here is to use the Sysinternals junction tool
#    to create a hard link between an "openssl-1.x" sub-directory of the
#    Fossil source code directory and the target OpenSSL source directory.
#
OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1g
OPENSSLINCDIR = $(OPENSSLDIR)/include
OPENSSLLIBDIR = $(OPENSSLDIR)

#### Either the directory where the Tcl library is installed or the Tcl
#    source code directory resides (depending on the value of the macro
#    FOSSIL_TCL_SOURCE).  If this points to the Tcl install directory,
#    this directory must have "include" and "lib" sub-directories.  If
438
439
440
441
442
443
444

445
446
447
448
449
450
451
XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR)

SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/alerts.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/attach.c \

  $(SRCDIR)/backoffice.c \
  $(SRCDIR)/bag.c \
  $(SRCDIR)/bisect.c \
  $(SRCDIR)/blob.c \
  $(SRCDIR)/branch.c \
  $(SRCDIR)/browse.c \
  $(SRCDIR)/builtin.c \







>







438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR)

SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/alerts.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/attach.c \
  $(SRCDIR)/backlink.c \
  $(SRCDIR)/backoffice.c \
  $(SRCDIR)/bag.c \
  $(SRCDIR)/bisect.c \
  $(SRCDIR)/blob.c \
  $(SRCDIR)/branch.c \
  $(SRCDIR)/browse.c \
  $(SRCDIR)/builtin.c \
631
632
633
634
635
636
637

638
639
640
641
642
643
644
645
646
647
648
649
650
















651
652
653
654
655
656
657
658
659

660
661
662
663
664
665
666
  $(SRCDIR)/../skins/rounded1/details.txt \
  $(SRCDIR)/../skins/rounded1/footer.txt \
  $(SRCDIR)/../skins/rounded1/header.txt \
  $(SRCDIR)/../skins/xekri/css.txt \
  $(SRCDIR)/../skins/xekri/details.txt \
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \

  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
















  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/alerts_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \

  $(OBJDIR)/backoffice_.c \
  $(OBJDIR)/bag_.c \
  $(OBJDIR)/bisect_.c \
  $(OBJDIR)/blob_.c \
  $(OBJDIR)/branch_.c \
  $(OBJDIR)/browse_.c \
  $(OBJDIR)/builtin_.c \







>













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









>







632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
  $(SRCDIR)/../skins/rounded1/details.txt \
  $(SRCDIR)/../skins/rounded1/footer.txt \
  $(SRCDIR)/../skins/rounded1/header.txt \
  $(SRCDIR)/../skins/xekri/css.txt \
  $(SRCDIR)/../skins/xekri/details.txt \
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \
  $(SRCDIR)/accordion.js \
  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \
  $(SRCDIR)/sounds/4.wav \
  $(SRCDIR)/sounds/5.wav \
  $(SRCDIR)/sounds/6.wav \
  $(SRCDIR)/sounds/7.wav \
  $(SRCDIR)/sounds/8.wav \
  $(SRCDIR)/sounds/9.wav \
  $(SRCDIR)/sounds/a.wav \
  $(SRCDIR)/sounds/b.wav \
  $(SRCDIR)/sounds/c.wav \
  $(SRCDIR)/sounds/d.wav \
  $(SRCDIR)/sounds/e.wav \
  $(SRCDIR)/sounds/f.wav \
  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/alerts_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \
  $(OBJDIR)/backlink_.c \
  $(OBJDIR)/backoffice_.c \
  $(OBJDIR)/bag_.c \
  $(OBJDIR)/bisect_.c \
  $(OBJDIR)/blob_.c \
  $(OBJDIR)/branch_.c \
  $(OBJDIR)/browse_.c \
  $(OBJDIR)/builtin_.c \
794
795
796
797
798
799
800

801
802
803
804
805
806
807
  $(OBJDIR)/zip_.c

OBJ = \
 $(OBJDIR)/add.o \
 $(OBJDIR)/alerts.o \
 $(OBJDIR)/allrepo.o \
 $(OBJDIR)/attach.o \

 $(OBJDIR)/backoffice.o \
 $(OBJDIR)/bag.o \
 $(OBJDIR)/bisect.o \
 $(OBJDIR)/blob.o \
 $(OBJDIR)/branch.o \
 $(OBJDIR)/browse.o \
 $(OBJDIR)/builtin.o \







>







813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
  $(OBJDIR)/zip_.c

OBJ = \
 $(OBJDIR)/add.o \
 $(OBJDIR)/alerts.o \
 $(OBJDIR)/allrepo.o \
 $(OBJDIR)/attach.o \
 $(OBJDIR)/backlink.o \
 $(OBJDIR)/backoffice.o \
 $(OBJDIR)/bag.o \
 $(OBJDIR)/bisect.o \
 $(OBJDIR)/blob.o \
 $(OBJDIR)/branch.o \
 $(OBJDIR)/browse.o \
 $(OBJDIR)/builtin.o \
1155
1156
1157
1158
1159
1160
1161

1162
1163
1164
1165
1166
1167
1168
	$(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@

$(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
	$(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
		$(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \
		$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
		$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \

		$(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \
		$(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \
		$(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \
		$(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \
		$(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \
		$(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \
		$(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \







>







1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
	$(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@

$(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
	$(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
		$(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \
		$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
		$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
		$(OBJDIR)/backlink_.c:$(OBJDIR)/backlink.h \
		$(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \
		$(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \
		$(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \
		$(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \
		$(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \
		$(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \
		$(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \
1330
1331
1332
1333
1334
1335
1336








1337
1338
1339
1340
1341
1342
1343
$(OBJDIR)/attach_.c:	$(SRCDIR)/attach.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/attach.c >$@

$(OBJDIR)/attach.o:	$(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c

$(OBJDIR)/attach.h:	$(OBJDIR)/headers









$(OBJDIR)/backoffice_.c:	$(SRCDIR)/backoffice.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/backoffice.c >$@

$(OBJDIR)/backoffice.o:	$(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c








>
>
>
>
>
>
>
>







1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
$(OBJDIR)/attach_.c:	$(SRCDIR)/attach.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/attach.c >$@

$(OBJDIR)/attach.o:	$(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c

$(OBJDIR)/attach.h:	$(OBJDIR)/headers

$(OBJDIR)/backlink_.c:	$(SRCDIR)/backlink.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/backlink.c >$@

$(OBJDIR)/backlink.o:	$(OBJDIR)/backlink_.c $(OBJDIR)/backlink.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backlink.o -c $(OBJDIR)/backlink_.c

$(OBJDIR)/backlink.h:	$(OBJDIR)/headers

$(OBJDIR)/backoffice_.c:	$(SRCDIR)/backoffice.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/backoffice.c >$@

$(OBJDIR)/backoffice.o:	$(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c

2438
2439
2440
2441
2442
2443
2444

2445
2446
2447
2448
2449
2450
2451
                 -DSQLITE_ENABLE_DBSTAT_VTAB \
                 -DSQLITE_ENABLE_JSON1 \
                 -DSQLITE_ENABLE_FTS5 \
                 -DSQLITE_ENABLE_STMTVTAB \
                 -DSQLITE_HAVE_ZLIB \
                 -DSQLITE_INTROSPECTION_PRAGMAS \
                 -DSQLITE_ENABLE_DBPAGE_VTAB \

                 -DSQLITE_WIN32_NO_ANSI \
                 $(MINGW_OPTIONS) \
                 -DSQLITE_USE_MALLOC_H \
                 -DSQLITE_USE_MSIZE

SHELL_OPTIONS = -DNDEBUG=1 \
                -DSQLITE_DQS=0 \







>







2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
                 -DSQLITE_ENABLE_DBSTAT_VTAB \
                 -DSQLITE_ENABLE_JSON1 \
                 -DSQLITE_ENABLE_FTS5 \
                 -DSQLITE_ENABLE_STMTVTAB \
                 -DSQLITE_HAVE_ZLIB \
                 -DSQLITE_INTROSPECTION_PRAGMAS \
                 -DSQLITE_ENABLE_DBPAGE_VTAB \
                 -DSQLITE_TRUSTED_SCHEMA=0 \
                 -DSQLITE_WIN32_NO_ANSI \
                 $(MINGW_OPTIONS) \
                 -DSQLITE_USE_MALLOC_H \
                 -DSQLITE_USE_MSIZE

SHELL_OPTIONS = -DNDEBUG=1 \
                -DSQLITE_DQS=0 \
2468
2469
2470
2471
2472
2473
2474

2475
2476
2477
2478
2479
2480
2481
                -DSQLITE_ENABLE_DBSTAT_VTAB \
                -DSQLITE_ENABLE_JSON1 \
                -DSQLITE_ENABLE_FTS5 \
                -DSQLITE_ENABLE_STMTVTAB \
                -DSQLITE_HAVE_ZLIB \
                -DSQLITE_INTROSPECTION_PRAGMAS \
                -DSQLITE_ENABLE_DBPAGE_VTAB \

                -Dmain=sqlite3_shell \
                -DSQLITE_SHELL_IS_UTF8=1 \
                -DSQLITE_OMIT_LOAD_EXTENSION=1 \
                -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
                -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
                -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
                -Daccess=file_access \







>







2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
                -DSQLITE_ENABLE_DBSTAT_VTAB \
                -DSQLITE_ENABLE_JSON1 \
                -DSQLITE_ENABLE_FTS5 \
                -DSQLITE_ENABLE_STMTVTAB \
                -DSQLITE_HAVE_ZLIB \
                -DSQLITE_INTROSPECTION_PRAGMAS \
                -DSQLITE_ENABLE_DBPAGE_VTAB \
                -DSQLITE_TRUSTED_SCHEMA=0 \
                -Dmain=sqlite3_shell \
                -DSQLITE_SHELL_IS_UTF8=1 \
                -DSQLITE_OMIT_LOAD_EXTENSION=1 \
                -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
                -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
                -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
                -Daccess=file_access \
Changes to win/Makefile.mingw.mistachkin.
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
endif

#### The directories where the OpenSSL include and library files are located.
#    The recommended usage here is to use the Sysinternals junction tool
#    to create a hard link between an "openssl-1.x" sub-directory of the
#    Fossil source code directory and the target OpenSSL source directory.
#
OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1d
OPENSSLINCDIR = $(OPENSSLDIR)/include
OPENSSLLIBDIR = $(OPENSSLDIR)

#### Either the directory where the Tcl library is installed or the Tcl
#    source code directory resides (depending on the value of the macro
#    FOSSIL_TCL_SOURCE).  If this points to the Tcl install directory,
#    this directory must have "include" and "lib" sub-directories.  If







|







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
endif

#### The directories where the OpenSSL include and library files are located.
#    The recommended usage here is to use the Sysinternals junction tool
#    to create a hard link between an "openssl-1.x" sub-directory of the
#    Fossil source code directory and the target OpenSSL source directory.
#
OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1g
OPENSSLINCDIR = $(OPENSSLDIR)/include
OPENSSLLIBDIR = $(OPENSSLDIR)

#### Either the directory where the Tcl library is installed or the Tcl
#    source code directory resides (depending on the value of the macro
#    FOSSIL_TCL_SOURCE).  If this points to the Tcl install directory,
#    this directory must have "include" and "lib" sub-directories.  If
438
439
440
441
442
443
444

445
446
447
448
449
450
451
XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR)

SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/alerts.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/attach.c \

  $(SRCDIR)/backoffice.c \
  $(SRCDIR)/bag.c \
  $(SRCDIR)/bisect.c \
  $(SRCDIR)/blob.c \
  $(SRCDIR)/branch.c \
  $(SRCDIR)/browse.c \
  $(SRCDIR)/builtin.c \







>







438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR)

SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/alerts.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/attach.c \
  $(SRCDIR)/backlink.c \
  $(SRCDIR)/backoffice.c \
  $(SRCDIR)/bag.c \
  $(SRCDIR)/bisect.c \
  $(SRCDIR)/blob.c \
  $(SRCDIR)/branch.c \
  $(SRCDIR)/browse.c \
  $(SRCDIR)/builtin.c \
631
632
633
634
635
636
637

638
639
640
641
642
643
644
645
646
647
648
649
650
















651
652
653
654
655
656
657
658
659

660
661
662
663
664
665
666
  $(SRCDIR)/../skins/rounded1/details.txt \
  $(SRCDIR)/../skins/rounded1/footer.txt \
  $(SRCDIR)/../skins/rounded1/header.txt \
  $(SRCDIR)/../skins/xekri/css.txt \
  $(SRCDIR)/../skins/xekri/details.txt \
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \

  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
















  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/alerts_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \

  $(OBJDIR)/backoffice_.c \
  $(OBJDIR)/bag_.c \
  $(OBJDIR)/bisect_.c \
  $(OBJDIR)/blob_.c \
  $(OBJDIR)/branch_.c \
  $(OBJDIR)/browse_.c \
  $(OBJDIR)/builtin_.c \







>













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









>







632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
  $(SRCDIR)/../skins/rounded1/details.txt \
  $(SRCDIR)/../skins/rounded1/footer.txt \
  $(SRCDIR)/../skins/rounded1/header.txt \
  $(SRCDIR)/../skins/xekri/css.txt \
  $(SRCDIR)/../skins/xekri/details.txt \
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \
  $(SRCDIR)/accordion.js \
  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \
  $(SRCDIR)/sounds/4.wav \
  $(SRCDIR)/sounds/5.wav \
  $(SRCDIR)/sounds/6.wav \
  $(SRCDIR)/sounds/7.wav \
  $(SRCDIR)/sounds/8.wav \
  $(SRCDIR)/sounds/9.wav \
  $(SRCDIR)/sounds/a.wav \
  $(SRCDIR)/sounds/b.wav \
  $(SRCDIR)/sounds/c.wav \
  $(SRCDIR)/sounds/d.wav \
  $(SRCDIR)/sounds/e.wav \
  $(SRCDIR)/sounds/f.wav \
  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/alerts_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \
  $(OBJDIR)/backlink_.c \
  $(OBJDIR)/backoffice_.c \
  $(OBJDIR)/bag_.c \
  $(OBJDIR)/bisect_.c \
  $(OBJDIR)/blob_.c \
  $(OBJDIR)/branch_.c \
  $(OBJDIR)/browse_.c \
  $(OBJDIR)/builtin_.c \
794
795
796
797
798
799
800

801
802
803
804
805
806
807
  $(OBJDIR)/zip_.c

OBJ = \
 $(OBJDIR)/add.o \
 $(OBJDIR)/alerts.o \
 $(OBJDIR)/allrepo.o \
 $(OBJDIR)/attach.o \

 $(OBJDIR)/backoffice.o \
 $(OBJDIR)/bag.o \
 $(OBJDIR)/bisect.o \
 $(OBJDIR)/blob.o \
 $(OBJDIR)/branch.o \
 $(OBJDIR)/browse.o \
 $(OBJDIR)/builtin.o \







>







813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
  $(OBJDIR)/zip_.c

OBJ = \
 $(OBJDIR)/add.o \
 $(OBJDIR)/alerts.o \
 $(OBJDIR)/allrepo.o \
 $(OBJDIR)/attach.o \
 $(OBJDIR)/backlink.o \
 $(OBJDIR)/backoffice.o \
 $(OBJDIR)/bag.o \
 $(OBJDIR)/bisect.o \
 $(OBJDIR)/blob.o \
 $(OBJDIR)/branch.o \
 $(OBJDIR)/browse.o \
 $(OBJDIR)/builtin.o \
1155
1156
1157
1158
1159
1160
1161

1162
1163
1164
1165
1166
1167
1168
	$(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@

$(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
	$(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
		$(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \
		$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
		$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \

		$(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \
		$(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \
		$(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \
		$(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \
		$(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \
		$(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \
		$(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \







>







1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
	$(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@

$(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
	$(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
		$(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \
		$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
		$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
		$(OBJDIR)/backlink_.c:$(OBJDIR)/backlink.h \
		$(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \
		$(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \
		$(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \
		$(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \
		$(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \
		$(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \
		$(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \
1330
1331
1332
1333
1334
1335
1336








1337
1338
1339
1340
1341
1342
1343
$(OBJDIR)/attach_.c:	$(SRCDIR)/attach.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/attach.c >$@

$(OBJDIR)/attach.o:	$(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c

$(OBJDIR)/attach.h:	$(OBJDIR)/headers









$(OBJDIR)/backoffice_.c:	$(SRCDIR)/backoffice.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/backoffice.c >$@

$(OBJDIR)/backoffice.o:	$(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c








>
>
>
>
>
>
>
>







1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
$(OBJDIR)/attach_.c:	$(SRCDIR)/attach.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/attach.c >$@

$(OBJDIR)/attach.o:	$(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c

$(OBJDIR)/attach.h:	$(OBJDIR)/headers

$(OBJDIR)/backlink_.c:	$(SRCDIR)/backlink.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/backlink.c >$@

$(OBJDIR)/backlink.o:	$(OBJDIR)/backlink_.c $(OBJDIR)/backlink.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backlink.o -c $(OBJDIR)/backlink_.c

$(OBJDIR)/backlink.h:	$(OBJDIR)/headers

$(OBJDIR)/backoffice_.c:	$(SRCDIR)/backoffice.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/backoffice.c >$@

$(OBJDIR)/backoffice.o:	$(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c

2438
2439
2440
2441
2442
2443
2444

2445
2446
2447
2448
2449
2450
2451
                 -DSQLITE_ENABLE_DBSTAT_VTAB \
                 -DSQLITE_ENABLE_JSON1 \
                 -DSQLITE_ENABLE_FTS5 \
                 -DSQLITE_ENABLE_STMTVTAB \
                 -DSQLITE_HAVE_ZLIB \
                 -DSQLITE_INTROSPECTION_PRAGMAS \
                 -DSQLITE_ENABLE_DBPAGE_VTAB \

                 -DSQLITE_WIN32_NO_ANSI \
                 $(MINGW_OPTIONS) \
                 -DSQLITE_USE_MALLOC_H \
                 -DSQLITE_USE_MSIZE

SHELL_OPTIONS = -DNDEBUG=1 \
                -DSQLITE_DQS=0 \







>







2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
                 -DSQLITE_ENABLE_DBSTAT_VTAB \
                 -DSQLITE_ENABLE_JSON1 \
                 -DSQLITE_ENABLE_FTS5 \
                 -DSQLITE_ENABLE_STMTVTAB \
                 -DSQLITE_HAVE_ZLIB \
                 -DSQLITE_INTROSPECTION_PRAGMAS \
                 -DSQLITE_ENABLE_DBPAGE_VTAB \
                 -DSQLITE_TRUSTED_SCHEMA=0 \
                 -DSQLITE_WIN32_NO_ANSI \
                 $(MINGW_OPTIONS) \
                 -DSQLITE_USE_MALLOC_H \
                 -DSQLITE_USE_MSIZE

SHELL_OPTIONS = -DNDEBUG=1 \
                -DSQLITE_DQS=0 \
2468
2469
2470
2471
2472
2473
2474

2475
2476
2477
2478
2479
2480
2481
                -DSQLITE_ENABLE_DBSTAT_VTAB \
                -DSQLITE_ENABLE_JSON1 \
                -DSQLITE_ENABLE_FTS5 \
                -DSQLITE_ENABLE_STMTVTAB \
                -DSQLITE_HAVE_ZLIB \
                -DSQLITE_INTROSPECTION_PRAGMAS \
                -DSQLITE_ENABLE_DBPAGE_VTAB \

                -Dmain=sqlite3_shell \
                -DSQLITE_SHELL_IS_UTF8=1 \
                -DSQLITE_OMIT_LOAD_EXTENSION=1 \
                -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
                -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
                -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
                -Daccess=file_access \







>







2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
                -DSQLITE_ENABLE_DBSTAT_VTAB \
                -DSQLITE_ENABLE_JSON1 \
                -DSQLITE_ENABLE_FTS5 \
                -DSQLITE_ENABLE_STMTVTAB \
                -DSQLITE_HAVE_ZLIB \
                -DSQLITE_INTROSPECTION_PRAGMAS \
                -DSQLITE_ENABLE_DBPAGE_VTAB \
                -DSQLITE_TRUSTED_SCHEMA=0 \
                -Dmain=sqlite3_shell \
                -DSQLITE_SHELL_IS_UTF8=1 \
                -DSQLITE_OMIT_LOAD_EXTENSION=1 \
                -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
                -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
                -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
                -Daccess=file_access \
Changes to win/Makefile.msc.
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

# Enable support for the SQLite Encryption Extension?
!ifndef USE_SEE
USE_SEE = 0
!endif

!if $(FOSSIL_ENABLE_SSL)!=0
SSLDIR    = $(B)\compat\openssl-1.1.1d
SSLINCDIR = $(SSLDIR)\include
!if $(FOSSIL_DYNAMIC_BUILD)!=0
SSLLIBDIR = $(SSLDIR)
!else
SSLLIBDIR = $(SSLDIR)
!endif
SSLLFLAGS = /nologo /opt:ref /debug







|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

# Enable support for the SQLite Encryption Extension?
!ifndef USE_SEE
USE_SEE = 0
!endif

!if $(FOSSIL_ENABLE_SSL)!=0
SSLDIR    = $(B)\compat\openssl-1.1.1g
SSLINCDIR = $(SSLDIR)\include
!if $(FOSSIL_DYNAMIC_BUILD)!=0
SSLLIBDIR = $(SSLDIR)
!else
SSLLIBDIR = $(SSLDIR)
!endif
SSLLFLAGS = /nologo /opt:ref /debug
298
299
300
301
302
303
304

305
306
307
308
309
310
311
                 /DSQLITE_ENABLE_DBSTAT_VTAB \
                 /DSQLITE_ENABLE_JSON1 \
                 /DSQLITE_ENABLE_FTS5 \
                 /DSQLITE_ENABLE_STMTVTAB \
                 /DSQLITE_HAVE_ZLIB \
                 /DSQLITE_INTROSPECTION_PRAGMAS \
                 /DSQLITE_ENABLE_DBPAGE_VTAB \

                 /DSQLITE_WIN32_NO_ANSI

SHELL_OPTIONS = /DNDEBUG=1 \
                /DSQLITE_DQS=0 \
                /DSQLITE_THREADSAFE=0 \
                /DSQLITE_DEFAULT_MEMSTATUS=0 \
                /DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \







>







298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
                 /DSQLITE_ENABLE_DBSTAT_VTAB \
                 /DSQLITE_ENABLE_JSON1 \
                 /DSQLITE_ENABLE_FTS5 \
                 /DSQLITE_ENABLE_STMTVTAB \
                 /DSQLITE_HAVE_ZLIB \
                 /DSQLITE_INTROSPECTION_PRAGMAS \
                 /DSQLITE_ENABLE_DBPAGE_VTAB \
                 /DSQLITE_TRUSTED_SCHEMA=0 \
                 /DSQLITE_WIN32_NO_ANSI

SHELL_OPTIONS = /DNDEBUG=1 \
                /DSQLITE_DQS=0 \
                /DSQLITE_THREADSAFE=0 \
                /DSQLITE_DEFAULT_MEMSTATUS=0 \
                /DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
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
                /DSQLITE_ENABLE_DBSTAT_VTAB \
                /DSQLITE_ENABLE_JSON1 \
                /DSQLITE_ENABLE_FTS5 \
                /DSQLITE_ENABLE_STMTVTAB \
                /DSQLITE_HAVE_ZLIB \
                /DSQLITE_INTROSPECTION_PRAGMAS \
                /DSQLITE_ENABLE_DBPAGE_VTAB \

                /Dmain=sqlite3_shell \
                /DSQLITE_SHELL_IS_UTF8=1 \
                /DSQLITE_OMIT_LOAD_EXTENSION=1 \
                /DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
                /DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
                /DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
                /Daccess=file_access \
                /Dsystem=fossil_system \
                /Dgetenv=fossil_getenv \
                /Dfopen=fossil_fopen

MINIZ_OPTIONS = /DMINIZ_NO_STDIO \
                /DMINIZ_NO_TIME \
                /DMINIZ_NO_ARCHIVE_APIS

SRC   = add_.c \
        alerts_.c \
        allrepo_.c \
        attach_.c \

        backoffice_.c \
        bag_.c \
        bisect_.c \
        blob_.c \
        branch_.c \
        browse_.c \
        builtin_.c \







>



















>







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
                /DSQLITE_ENABLE_DBSTAT_VTAB \
                /DSQLITE_ENABLE_JSON1 \
                /DSQLITE_ENABLE_FTS5 \
                /DSQLITE_ENABLE_STMTVTAB \
                /DSQLITE_HAVE_ZLIB \
                /DSQLITE_INTROSPECTION_PRAGMAS \
                /DSQLITE_ENABLE_DBPAGE_VTAB \
                /DSQLITE_TRUSTED_SCHEMA=0 \
                /Dmain=sqlite3_shell \
                /DSQLITE_SHELL_IS_UTF8=1 \
                /DSQLITE_OMIT_LOAD_EXTENSION=1 \
                /DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
                /DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
                /DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
                /Daccess=file_access \
                /Dsystem=fossil_system \
                /Dgetenv=fossil_getenv \
                /Dfopen=fossil_fopen

MINIZ_OPTIONS = /DMINIZ_NO_STDIO \
                /DMINIZ_NO_TIME \
                /DMINIZ_NO_ARCHIVE_APIS

SRC   = add_.c \
        alerts_.c \
        allrepo_.c \
        attach_.c \
        backlink_.c \
        backoffice_.c \
        bag_.c \
        bisect_.c \
        blob_.c \
        branch_.c \
        browse_.c \
        builtin_.c \
536
537
538
539
540
541
542

543
544
545
546
547
548
549
550
551
552
553
554
555
















556
557
558
559
560
561
562
563

564
565
566
567
568
569
570
        $(SRCDIR)\..\skins\rounded1\details.txt \
        $(SRCDIR)\..\skins\rounded1\footer.txt \
        $(SRCDIR)\..\skins\rounded1\header.txt \
        $(SRCDIR)\..\skins\xekri\css.txt \
        $(SRCDIR)\..\skins\xekri\details.txt \
        $(SRCDIR)\..\skins\xekri\footer.txt \
        $(SRCDIR)\..\skins\xekri\header.txt \

        $(SRCDIR)\ci_edit.js \
        $(SRCDIR)\copybtn.js \
        $(SRCDIR)\diff.tcl \
        $(SRCDIR)\forum.js \
        $(SRCDIR)\graph.js \
        $(SRCDIR)\href.js \
        $(SRCDIR)\login.js \
        $(SRCDIR)\markdown.md \
        $(SRCDIR)\menu.js \
        $(SRCDIR)\sbsdiff.js \
        $(SRCDIR)\scroll.js \
        $(SRCDIR)\skin.js \
        $(SRCDIR)\sorttable.js \
















        $(SRCDIR)\tree.js \
        $(SRCDIR)\useredit.js \
        $(SRCDIR)\wiki.wiki

OBJ   = $(OX)\add$O \
        $(OX)\alerts$O \
        $(OX)\allrepo$O \
        $(OX)\attach$O \

        $(OX)\backoffice$O \
        $(OX)\bag$O \
        $(OX)\bisect$O \
        $(OX)\blob$O \
        $(OX)\branch$O \
        $(OX)\browse$O \
        $(OX)\builtin$O \







>













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








>







539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
        $(SRCDIR)\..\skins\rounded1\details.txt \
        $(SRCDIR)\..\skins\rounded1\footer.txt \
        $(SRCDIR)\..\skins\rounded1\header.txt \
        $(SRCDIR)\..\skins\xekri\css.txt \
        $(SRCDIR)\..\skins\xekri\details.txt \
        $(SRCDIR)\..\skins\xekri\footer.txt \
        $(SRCDIR)\..\skins\xekri\header.txt \
        $(SRCDIR)\accordion.js \
        $(SRCDIR)\ci_edit.js \
        $(SRCDIR)\copybtn.js \
        $(SRCDIR)\diff.tcl \
        $(SRCDIR)\forum.js \
        $(SRCDIR)\graph.js \
        $(SRCDIR)\href.js \
        $(SRCDIR)\login.js \
        $(SRCDIR)\markdown.md \
        $(SRCDIR)\menu.js \
        $(SRCDIR)\sbsdiff.js \
        $(SRCDIR)\scroll.js \
        $(SRCDIR)\skin.js \
        $(SRCDIR)\sorttable.js \
        $(SRCDIR)\sounds\0.wav \
        $(SRCDIR)\sounds\1.wav \
        $(SRCDIR)\sounds\2.wav \
        $(SRCDIR)\sounds\3.wav \
        $(SRCDIR)\sounds\4.wav \
        $(SRCDIR)\sounds\5.wav \
        $(SRCDIR)\sounds\6.wav \
        $(SRCDIR)\sounds\7.wav \
        $(SRCDIR)\sounds\8.wav \
        $(SRCDIR)\sounds\9.wav \
        $(SRCDIR)\sounds\a.wav \
        $(SRCDIR)\sounds\b.wav \
        $(SRCDIR)\sounds\c.wav \
        $(SRCDIR)\sounds\d.wav \
        $(SRCDIR)\sounds\e.wav \
        $(SRCDIR)\sounds\f.wav \
        $(SRCDIR)\tree.js \
        $(SRCDIR)\useredit.js \
        $(SRCDIR)\wiki.wiki

OBJ   = $(OX)\add$O \
        $(OX)\alerts$O \
        $(OX)\allrepo$O \
        $(OX)\attach$O \
        $(OX)\backlink$O \
        $(OX)\backoffice$O \
        $(OX)\bag$O \
        $(OX)\bisect$O \
        $(OX)\blob$O \
        $(OX)\branch$O \
        $(OX)\browse$O \
        $(OX)\builtin$O \
760
761
762
763
764
765
766

767
768
769
770
771
772
773
		$(MTC) -nologo -manifest $@.manifest -outputresource:$@;1

$(OX)\linkopts: $B\win\Makefile.msc
	echo $(OX)\add.obj > $@
	echo $(OX)\alerts.obj >> $@
	echo $(OX)\allrepo.obj >> $@
	echo $(OX)\attach.obj >> $@

	echo $(OX)\backoffice.obj >> $@
	echo $(OX)\bag.obj >> $@
	echo $(OX)\bisect.obj >> $@
	echo $(OX)\blob.obj >> $@
	echo $(OX)\branch.obj >> $@
	echo $(OX)\browse.obj >> $@
	echo $(OX)\builtin.obj >> $@







>







781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
		$(MTC) -nologo -manifest $@.manifest -outputresource:$@;1

$(OX)\linkopts: $B\win\Makefile.msc
	echo $(OX)\add.obj > $@
	echo $(OX)\alerts.obj >> $@
	echo $(OX)\allrepo.obj >> $@
	echo $(OX)\attach.obj >> $@
	echo $(OX)\backlink.obj >> $@
	echo $(OX)\backoffice.obj >> $@
	echo $(OX)\bag.obj >> $@
	echo $(OX)\bisect.obj >> $@
	echo $(OX)\blob.obj >> $@
	echo $(OX)\branch.obj >> $@
	echo $(OX)\browse.obj >> $@
	echo $(OX)\builtin.obj >> $@
1042
1043
1044
1045
1046
1047
1048






1049
1050
1051
1052
1053
1054
1055
	translate$E $** > $@

$(OX)\attach$O : attach_.c attach.h
	$(TCC) /Fo$@ -c attach_.c

attach_.c : $(SRCDIR)\attach.c
	translate$E $** > $@







$(OX)\backoffice$O : backoffice_.c backoffice.h
	$(TCC) /Fo$@ -c backoffice_.c

backoffice_.c : $(SRCDIR)\backoffice.c
	translate$E $** > $@








>
>
>
>
>
>







1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
	translate$E $** > $@

$(OX)\attach$O : attach_.c attach.h
	$(TCC) /Fo$@ -c attach_.c

attach_.c : $(SRCDIR)\attach.c
	translate$E $** > $@

$(OX)\backlink$O : backlink_.c backlink.h
	$(TCC) /Fo$@ -c backlink_.c

backlink_.c : $(SRCDIR)\backlink.c
	translate$E $** > $@

$(OX)\backoffice$O : backoffice_.c backoffice.h
	$(TCC) /Fo$@ -c backoffice_.c

backoffice_.c : $(SRCDIR)\backoffice.c
	translate$E $** > $@

1861
1862
1863
1864
1865
1866
1867

1868
1869
1870
1871
1872
1873
1874
	$(RCC)  /fo $@ $**

headers: makeheaders$E page_index.h builtin_data.h default_css.h VERSION.h
	makeheaders$E add_.c:add.h \
			alerts_.c:alerts.h \
			allrepo_.c:allrepo.h \
			attach_.c:attach.h \

			backoffice_.c:backoffice.h \
			bag_.c:bag.h \
			bisect_.c:bisect.h \
			blob_.c:blob.h \
			branch_.c:branch.h \
			browse_.c:browse.h \
			builtin_.c:builtin.h \







>







1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
	$(RCC)  /fo $@ $**

headers: makeheaders$E page_index.h builtin_data.h default_css.h VERSION.h
	makeheaders$E add_.c:add.h \
			alerts_.c:alerts.h \
			allrepo_.c:allrepo.h \
			attach_.c:attach.h \
			backlink_.c:backlink.h \
			backoffice_.c:backoffice.h \
			bag_.c:bag.h \
			bisect_.c:bisect.h \
			blob_.c:blob.h \
			branch_.c:branch.h \
			browse_.c:browse.h \
			builtin_.c:builtin.h \
Changes to www/adding_code.wiki.
1
2
3
4
5
6






7
8
9
10
11
12
13
<title>Adding Features To Fossil</title>

<h2>1.0 Introduction</h2>

This article provides a brief overview of how to write new code that extends
or enhances Fossil.







<h2>2.0 Programming Language</h2>

Fossil is written in C-89.  There are specific [./style.wiki | style guidelines]
that are required for any new code that will be accepted into the Fossil core.
But, of course, if you are writing an extension just for yourself, you can
use any programming style you want.




|
|
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<title>Adding Features To Fossil</title>

<h2>1.0 Introduction</h2>

This article provides a brief overview of how to write new C-code code that
extends or enhances the core Fossil binary.

New features can be added to a Fossil server using
[./serverext.wiki|external CGI programs],
but that is not what this article is about.
This article focuses on how to make changes
to Fossil itself.

<h2>2.0 Programming Language</h2>

Fossil is written in C-89.  There are specific [./style.wiki | style guidelines]
that are required for any new code that will be accepted into the Fossil core.
But, of course, if you are writing an extension just for yourself, you can
use any programming style you want.
94
95
96
97
98
99
100

101
102
103
104
105
106
107
the makefiles, you should be able to recompile Fossil and have it include
your new source file, even before you source file contains any code.
It is recommended that you try this.

Be sure to [/help/add|fossil add] your new source file to the self-hosting
Fossil repository and then [/help/commit|commit] your changes!


<h2>4.0 Creating A New Command</h2>

By "commands" we mean the keywords that follow "fossil" when invoking
Fossil from the command-line.  So, for example, in

    <b>fossil diff xyzzy.c</b>








>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
the makefiles, you should be able to recompile Fossil and have it include
your new source file, even before you source file contains any code.
It is recommended that you try this.

Be sure to [/help/add|fossil add] your new source file to the self-hosting
Fossil repository and then [/help/commit|commit] your changes!

<a name="newcmd"></a>
<h2>4.0 Creating A New Command</h2>

By "commands" we mean the keywords that follow "fossil" when invoking
Fossil from the command-line.  So, for example, in

    <b>fossil diff xyzzy.c</b>

159
160
161
162
163
164
165

166
167
168
169
170
171
172
Fossil for parsing command-line options and for
opening and accessing and manipulating the repository and
the working check-out.  Study implementations of existing commands
to get an idea of how things are done.  You can easily find the implementations
of existing commands by searching for "COMMAND: <i>name</i>" in the
files of the "src/" directory.


<h2>5.0 Creating A New Web Page</h2>

As with commands, new webpages can be added simply by inserting a function
that generates the webpage together with a special header comment.  A
template follows:

<blockquote><verbatim>







>







166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
Fossil for parsing command-line options and for
opening and accessing and manipulating the repository and
the working check-out.  Study implementations of existing commands
to get an idea of how things are done.  You can easily find the implementations
of existing commands by searching for "COMMAND: <i>name</i>" in the
files of the "src/" directory.

<a name="newpage"></a>
<h2>5.0 Creating A New Web Page</h2>

As with commands, new webpages can be added simply by inserting a function
that generates the webpage together with a special header comment.  A
template follows:

<blockquote><verbatim>
209
210
211
212
213
214
215

works.

<h2>6.0 See Also</h2>

  *  [./makefile.wiki|The Fossil Build Process]
  *  [./tech_overview.wiki|A Technical Overview Of Fossil]
  *  [./contribute.wiki|Contributing To The Fossil Project]








>
217
218
219
220
221
222
223
224
works.

<h2>6.0 See Also</h2>

  *  [./makefile.wiki|The Fossil Build Process]
  *  [./tech_overview.wiki|A Technical Overview Of Fossil]
  *  [./contribute.wiki|Contributing To The Fossil Project]
  *  [./serverext.wiki|Adding CGI Extensions To A Fossil Server]
Changes to www/alerts.md.
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
### Internal Processing Flow

Almost all of the email alert code is found in the
[`src/alerts.c`](/file/src/alerts.c) source file.

When email alerts are enabled, a trigger is created in the schema
(`email_trigger1`) that adds a new entry to the `PENDING_ALERT` table
every time a row is added to the `EVENT` table.  During a `fossil
rebuild`, the `EVENT` table is rebuilt from scratch; since we do not
want users to get alerts for every historical check-in, the trigger is
disabled during `rebuild`.

Email alerts are sent out by the `alert_send_alerts()` function, which
is normally called automatically due to the `email-autoexec` setting,
which defaults to enabled. If that setting is disabled or if the user
simply wants to force email alerts to be sent immediately, they can give







|
|







716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
### Internal Processing Flow

Almost all of the email alert code is found in the
[`src/alerts.c`](/file/src/alerts.c) source file.

When email alerts are enabled, a trigger is created in the schema
(`email_trigger1`) that adds a new entry to the `PENDING_ALERT` table
every time a row is added to the `EVENT` table.  During a 
`fossil rebuild`, the `EVENT` table is rebuilt from scratch; since we do not
want users to get alerts for every historical check-in, the trigger is
disabled during `rebuild`.

Email alerts are sent out by the `alert_send_alerts()` function, which
is normally called automatically due to the `email-autoexec` setting,
which defaults to enabled. If that setting is disabled or if the user
simply wants to force email alerts to be sent immediately, they can give
Changes to www/antibot.wiki.
1
2
3
4
5
6
7
8
9
10
11
12
13
<title>Defense Against Spiders</title>

The website presented by a Fossil server has many hyperlinks.
Even a modest project can have millions of pages in its
tree, and many of those pages (for example diffs and annotations
and ZIP archive of older check-ins) can be expensive to compute.
If a spider or bot tries to walk a website implemented by
Fossil, it can present a crippling bandwidth and CPU load.

The website presented by a Fossil server is intended to be used
interactively by humans, not walked by spiders.  This article
describes the techniques used by Fossil to try to welcome human
users while keeping out spiders.





|







1
2
3
4
5
6
7
8
9
10
11
12
13
<title>Defense Against Spiders</title>

The website presented by a Fossil server has many hyperlinks.
Even a modest project can have millions of pages in its
tree, and many of those pages (for example diffs and annotations
and ZIP archives of older check-ins) can be expensive to compute.
If a spider or bot tries to walk a website implemented by
Fossil, it can present a crippling bandwidth and CPU load.

The website presented by a Fossil server is intended to be used
interactively by humans, not walked by spiders.  This article
describes the techniques used by Fossil to try to welcome human
users while keeping out spiders.
Changes to www/blockchain.md.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   block, a timestamp, and transaction data..." [(1)][]


By that definition, Fossil is clearly an implementation of blockchain.
The blocks are ["manifests" artifacts](./fileformat.wiki#manifest).
Each manifest has a SHA1 or SHA3 hash of its parent or parents,
a timestamp, and other transactional data.  The repository grows by
add new manifests onto the list.

Some people have come to associate blockchain with cryptocurrency, however,
and since Fossil has nothing to do with cryptocurrency, the claim that
Fossil is build around blockchain is met with skepticism.  The key thing
to note here is that cryptocurrency implementations like BitCoin are
built around blockchain, but they are not synonymous with blockchain.
Blockchain is a much broader concept.  Blockchain is a mechanism for
constructed a distributed ledger of transactions.
Yes, you can use a distributed
ledger to implement a cryptocurrency, but you can also use a distributed
ledger to implement a version control system, and probably many other kinds
of applications as well.  Blockchain is a much broader idea than
cryptocurrency.

[(1)]: https://en.wikipedia.org/wiki/Blockchain







|



|



|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   block, a timestamp, and transaction data..." [(1)][]


By that definition, Fossil is clearly an implementation of blockchain.
The blocks are ["manifests" artifacts](./fileformat.wiki#manifest).
Each manifest has a SHA1 or SHA3 hash of its parent or parents,
a timestamp, and other transactional data.  The repository grows by
adding new manifests onto the list.

Some people have come to associate blockchain with cryptocurrency, however,
and since Fossil has nothing to do with cryptocurrency, the claim that
Fossil is built around blockchain is met with skepticism.  The key thing
to note here is that cryptocurrency implementations like BitCoin are
built around blockchain, but they are not synonymous with blockchain.
Blockchain is a much broader concept.  Blockchain is a mechanism for
constructing a distributed ledger of transactions.
Yes, you can use a distributed
ledger to implement a cryptocurrency, but you can also use a distributed
ledger to implement a version control system, and probably many other kinds
of applications as well.  Blockchain is a much broader idea than
cryptocurrency.

[(1)]: https://en.wikipedia.org/wiki/Blockchain
Changes to www/build.wiki.
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
file "<b>win\buildmsvc.bat</b>" may be used and it will attempt to
detect and use the latest installed version of MSVC.<br><br>To enable
the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
first <a href="https://www.openssl.org/source/">download the official
source code for OpenSSL</a> and extract it to an appropriately named
"<b>openssl-X.Y.ZA</b>" subdirectory within the local
[/tree?ci=trunk&name=compat | compat] directory (e.g.
"<b>compat/openssl-1.1.1d</b>"), then make sure that some recent
<a href="http://www.perl.org/">Perl</a> binaries are installed locally,
and finally run one of the following commands:
<blockquote><pre>
nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
</pre></blockquote>
<blockquote><pre>
buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin







|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
file "<b>win\buildmsvc.bat</b>" may be used and it will attempt to
detect and use the latest installed version of MSVC.<br><br>To enable
the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
first <a href="https://www.openssl.org/source/">download the official
source code for OpenSSL</a> and extract it to an appropriately named
"<b>openssl-X.Y.ZA</b>" subdirectory within the local
[/tree?ci=trunk&name=compat | compat] directory (e.g.
"<b>compat/openssl-1.1.1g</b>"), then make sure that some recent
<a href="http://www.perl.org/">Perl</a> binaries are installed locally,
and finally run one of the following commands:
<blockquote><pre>
nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
</pre></blockquote>
<blockquote><pre>
buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
308
309
310
311
312
313
314





















































<pre><code># docker container rm fossil
# docker image ls
</code></pre>

Note the IDs of the images named <tt>fossil_static</tt> and <tt>alpine</tt>, then:

<pre><code>docker image rm THE_FOSSIL_ID THE_ALPINE_ID</code></pre>




























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
<pre><code># docker container rm fossil
# docker image ls
</code></pre>

Note the IDs of the images named <tt>fossil_static</tt> and <tt>alpine</tt>, then:

<pre><code>docker image rm THE_FOSSIL_ID THE_ALPINE_ID</code></pre>


<h2>6.0 Building on/for Android</h2>

<h3>6.1 Cross-compiling from Linux</h3>

The following instructions for building Fossil for Andoid,
without requiring a rooted OS, are adapted from
[https://fossil-scm.org/forum/forumpost/e0e9de4a7e | forumpost/e0e9de4a7e].

On the development machine, from the fossil source tree:

<pre><code>export CC=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang
./configure --with-openssl=none
make
</code></pre>


On the Android device, enable the <em>USB debugging</em> option from
Developer menu in Device Options. Connect the device to the development
system with USB. If it's configured and connected properly,
the device should show up in the output of <code>adb devices</code>:

<pre><code>sudo adb devices
</code></pre>

Copy the resulting fossil binary onto the device...

<pre><code>sudo adb push fossil /data/local/tmp
</code></pre>

And run it from an <code>adb</code> shell:

<pre><code>sudo adb shell
&gt; cd /data/local/tmp
# Fossil requires a HOME directory to work with:
&gt; export HOME=$PWD
&gt; export PATH=$PWD:$PATH
&gt; fossil version
This is fossil version 2.11 &#91;e5653a4ceb] 2020-03-26 18:54:02 UTC
</code></pre>

The output might, or might not, include warnings such as:

<pre><code>WARNING: linker: ./fossil: unused DT entry: type 0x6ffffef5 arg 0x1464
WARNING: linker: ./fossil: unused DT entry: type 0x6ffffffe arg 0x1ba8
WARNING: linker: ./fossil: unused DT entry: type 0x6fffffff arg 0x2
</code></pre>

The source of such warnings is not 100% certain.
Some information about these (reportedly harmless) warnings can
be found
[https://stackoverflow.com/a/41900551 | on this StackOverflow post].
Changes to www/caps/index.md.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

This is a complex topic, so some sub-topics have their own documents:

1.  [Login Groups][lg]
2.  [Implementation Details](./impl.md)
3.  [User Capability Reference](./ref.html)

[an]:   https://en.wikipediAsa.org/wiki/Alphanumeric
[avs]:  ./admin-v-setup.md
[lg]:   ./login-groups.md
[rbac]: https://en.wikipedia.org/wiki/Role-based_access_control


## <a name="ucat"></a>User Categories








|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

This is a complex topic, so some sub-topics have their own documents:

1.  [Login Groups][lg]
2.  [Implementation Details](./impl.md)
3.  [User Capability Reference](./ref.html)

[an]:   https://en.wikipedia.org/wiki/Alphanumeric
[avs]:  ./admin-v-setup.md
[lg]:   ./login-groups.md
[rbac]: https://en.wikipedia.org/wiki/Role-based_access_control


## <a name="ucat"></a>User Categories

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
category.

Fossil shows how these capabilities apply hierarchically in the user
editing screen (Admin → Users → name) with the `[N]` `[A]` `[D]` `[R]`
tags next to each capability check box. If a user gets a capability from
one of the user categories already assigned to it, there is no value in
redundantly assigning that same cap to the user explicitly. For example,
with the default **dei** cap set for the “developer” category, the cap
set **ve** is redundant because **v** grants **dei**, which includes
**e**.

We suggest that you lean heavily on these fixed user categories when
setting up new users. Ideally, your users will group neatly into one of
the predefined categories, but if not, you might be able to shoehorn
them into our fixed scheme. For example, the administrator of a
wiki-only Fossil repo for non-developers could treat the “developer”







|
|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
category.

Fossil shows how these capabilities apply hierarchically in the user
editing screen (Admin → Users → name) with the `[N]` `[A]` `[D]` `[R]`
tags next to each capability check box. If a user gets a capability from
one of the user categories already assigned to it, there is no value in
redundantly assigning that same cap to the user explicitly. For example,
with the default **ei** cap set for the “developer” category, the cap
set **ve** is redundant because **v** grants **ei**, which includes
**e**.

We suggest that you lean heavily on these fixed user categories when
setting up new users. Ideally, your users will group neatly into one of
the predefined categories, but if not, you might be able to shoehorn
them into our fixed scheme. For example, the administrator of a
wiki-only Fossil repo for non-developers could treat the “developer”
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
**[k][k][p][p][t][t][w][w]** caps to those granted by “nobody” and
“anonymous”. This category is not well-named, because the default caps
are all about modifying repository content: edit existing wiki pages,
change one’s own password, create new ticket report formats, and modify
existing tickets. This category would be better named “participant”.

Those in the “developer” category get the “nobody” and “anonymous” cap
sets plus **[d][d][e][e][i][i]**: delete wiki articles and tickets, view
sensitive user material, and check in changes.

[bot]: ../antibot.wiki


## <a name="pvt"></a>Consequences of Taking a Repository Private

When you click Admin → Security-Audit → “Take it private,” one of the







|
|







149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
**[k][k][p][p][t][t][w][w]** caps to those granted by “nobody” and
“anonymous”. This category is not well-named, because the default caps
are all about modifying repository content: edit existing wiki pages,
change one’s own password, create new ticket report formats, and modify
existing tickets. This category would be better named “participant”.

Those in the “developer” category get the “nobody” and “anonymous” cap
sets plus **[e][e][i][i]**: view
sensitive user material and check in changes.

[bot]: ../antibot.wiki


## <a name="pvt"></a>Consequences of Taking a Repository Private

When you click Admin → Security-Audit → “Take it private,” one of the
Changes to www/caps/ref.html.
71
72
73
74
75
76
77
78
79
80








81
82
83
84
85
86
87
88
89
    <td>
      Append comments to existing tickets. Mnemonic: <b>c</b>omment.
    </td>
  </tr> 

  <tr id="d">
    <th>d</th>
    <th>Delete</th>
    <td>
      Delete wiki articles or tickets. Mnemonic: <b>d</b>elete.








    </td>
  </tr> 

  <tr id="e">
    <th>e</th>
    <th>RdAddr</th>
    <td>
      View <a
      href="https://en.wikipedia.org/wiki/Personal_data">personal







|

|
>
>
>
>
>
>
>
>

|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    <td>
      Append comments to existing tickets. Mnemonic: <b>c</b>omment.
    </td>
  </tr> 

  <tr id="d">
    <th>d</th>
    <th>n/a</th>
    <td>
      Legacy capability letter from Fossil's forebear <a
      href="http://cvstrac.org/">CVSTrac</a>, which has no useful
      meaning in Fossil due to its durable blockchain nature. This
      letter was assigned by default to Developer in repos created with
      Fossil 2.10 or earlier, but it has no effect in current or past
      versions of Fossil; we recommend that you remove it in case we
      ever reuse this letter for another purpose. See <a
      href="https://fossil-scm.org/forum/forumpost/43c78f4bef">this
      post</a> for details.
    </td>
  </tr>

  <tr id="e">
    <th>e</th>
    <th>RdAddr</th>
    <td>
      View <a
      href="https://en.wikipedia.org/wiki/Personal_data">personal
Changes to www/cgi.wiki.
134
135
136
137
138
139
140






This parameter causes additional environment variable NAME to have VALUE.
This parameter can be repeated as many times as necessary.

<h2 id="HOME">HOME: <i>PATH</i></h2>

This parameter is a short-hand for "<b>setenv HOME <i>PATH</i></b>".












>
>
>
>
>
134
135
136
137
138
139
140
141
142
143
144
145

This parameter causes additional environment variable NAME to have VALUE.
This parameter can be repeated as many times as necessary.

<h2 id="HOME">HOME: <i>PATH</i></h2>

This parameter is a short-hand for "<b>setenv HOME <i>PATH</i></b>".

<h2 id="cgi-debug">cgi-debug: <i>FILE</i></h2>

Cause CGI-related debugging information to be appended in <i>FILE</i>.  Use
this to help debug CGI problems.
Changes to www/changes.wiki.
1
2
3
4
5
6

























7



















































8
9
10
11
12
13
14
<title>Change Log</title>

<a name='v2_11'></a>
<h2>Changes for Version 2.11 (pending)</h2>

  *  Support Markdown in the default ticket configuration

























  *  Rework the "fossil grep" command to be more useful




















































<a name='v2_10'></a>
<h2>Changes for Version 2.10 (2019-10-04)</h2>

  *  Added support for [./serverext.wiki|CGI-based Server Extensions].
  *  Added the [/help?cmd=repolist-skin|repolist-skin] setting used to
     add style to repository list pages.





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







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

<a name='v2_11'></a>
<h2>Changes for Version 2.11 (pending)</h2>

  *  Support [/md_rules|Markdown] in the default ticket configuration.
  *  Timestamp strings in [./checkin_names.wiki|object names]
     can now omit punctation.  So, for example, "202004181942" and
     "2020-04-18 19:42" mean the same thing.
  *  Enhance backlink processing so that it works with Markdown-formatted
     tickets and so that it works for wiki pages.
     Ticket [a3572c6a5b47cd5a].
     <ul><li> "[/help?cmd=rebuild|fossil rebuild]" is needed to
     take full advantage of this fix.  Fossil will continue
     to work without the rebuild, but the new backlinks will be missing.</ul>
  *  The algorithm for finding the
     [./tech_overview.wiki#configloc|location of the configuration database]
     is enhanced to be XDG-compliant.
  *  Add a hide/show feature to
     [./wikitheory.wiki#assocwiki|associated wiki] display on 
     check-in and branch information pages.
  *  Enhance the "[/help?cmd=info|fossil info]" command so that it
     works with no arguments even if not within an open check-out.
  *  Many improvements to the forum and especially email notification
     of forum posts, in response to community feedback after switching
     SQLite support from a mailing list over to the forum.
  *  Minimum length of a self-registered user ID increased from 3 to 6
     characters.
  *  When the "vfx" query parameter is used on the
     "[/help?cmd=/timeline|/timeline]" page, it causes the complete
     text of forum posts to be displayed.
  *  Rework the "[/help?cmd=grep|fossil grep]" command to be more useful.
  *  Expose the [/help?cmd=redirect-to-https|redirect-to-https]
     setting to the [/help?cmd=settings|settings] command.
  *  Improve support for CGI on IIS web servers.
  *  The [./serverext.wiki|/ext page] can now render index files,
     in the same way as the embedded docs.
  *  Most commands now support the Unix-conventional "<tt>--</tt>"
     flag to treat all following arguments as filenames
     instead of flags.
  *  Added the [/help?cmd=mimetypes|mimetypes config setting]
     (versionable) to enable mimetype overrides and custom definitions.
  *  Add an option on the /Admin/Timeline setup page to set a default
     timeline style other than "Modern".
  *  In [./embeddeddoc.wiki|embedded documentation], hyperlink URLs
     of the form "/doc/$CURRENT/..." the "$CURRENT" text is translated
     into the check-in hash for the document currently being viewed.
  *  Added the [/help?cmd=/phantoms|/phantoms] webpage that shows all
     phantom artifacts.
  *  Enhancements to phantom processing to try to reduce
     bandwidth-using chatter about phantoms on the sync protocol.
  *  Security: Fossil now assumes that the schema of every
     database it opens has been tampered with by an adversary and takes
     extra precautions to ensure that such tampering is harmless.
  *  Security: Fossil now puts the Content-Security-Policy in the
     HTTP reply header, in addition to also leaving it in the
     HTML &lt;head&gt; section, so that it is always available, even
     if a custom skin overrides the HTML &lt;head&gt; and omits
     the CSP in the process.
  *  The Content-Security-Policy is now set using the
     [/help?cmd=default-csp|default-csp setting].
  *  Merge conflicts caused via the [/help?cmd=merge|merge] and
     [/help?cmd=update|update] commands no longer leave temporary
     files behind unless the new <tt>--keep-merge-files</tt> flag
     is used.
  *  The [/help?cmd=/artifact_stats|/artifact_stats page] is now accessible
     to all users if the new "artifact_stats_enable" setting is turned
     on.  There is a new checkbox under the /Admin/Access menu to turn
     that capability on and off.
  *  Captchas all include a button to read the captcha using an audio
     file, so that they can be completed by the visually impaired.
  *  Stop using the IP address as part of the login cookie.
  *  Bug fix: the FTS search into for forum posts is now kept up-to-date
     correctly.
  *  Bug fix: the "fossil git export" command is now working on Windows
  *  Bug fix: display Technote items on the timeline correctly
  *  Bug fix: fix the capability summary matrix of the Security Audit
     page so that it does not add "anonymous" capabilities to the
     "nobody" user.
  *  Update internal Unicode character tables, used in regular expression
     handling, from version 12.1 to 13.
  *  Many documentation enhancements.
  *  Many minor enhancements to existing features.

<a name='v2_10'></a>
<h2>Changes for Version 2.10 (2019-10-04)</h2>

  *  Added support for [./serverext.wiki|CGI-based Server Extensions].
  *  Added the [/help?cmd=repolist-skin|repolist-skin] setting used to
     add style to repository list pages.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  *  Add hyperlinks to branch-diffs on the /info page and from
     timelines of a branch.
  *  Add graphical context on the [/help?cmd=/vdiff|/vdiff] page.
  *  Uppercase query parameters, POST parameters, and cookie names are
     converted to all lowercase and entered into the parameter set,
     instead of being discarded.
  *  Change the default [./hashpolicy.wiki|hash policy] to SHA3.
  *  Timeout [./server/any/cgi.md|CGI requests] after 300 seconds, or 
     some other value set by the 
     [./cgi.wiki#timeout|"timeout:" property] in the CGI script.
  *  The check-in lock interval is reduced from 24 hours to 60 seconds,
     though the interval is now configurable using a setting.
     An additional check for conflicts is added after interactive
     check-in comment entry, to compensate for the reduced lock interval.
  *  Performance optimizations.
  *  Many documentation improvements.







|
|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  *  Add hyperlinks to branch-diffs on the /info page and from
     timelines of a branch.
  *  Add graphical context on the [/help?cmd=/vdiff|/vdiff] page.
  *  Uppercase query parameters, POST parameters, and cookie names are
     converted to all lowercase and entered into the parameter set,
     instead of being discarded.
  *  Change the default [./hashpolicy.wiki|hash policy] to SHA3.
  *  Timeout [./server/any/cgi.md|CGI requests] after 300 seconds, or
     some other value set by the
     [./cgi.wiki#timeout|"timeout:" property] in the CGI script.
  *  The check-in lock interval is reduced from 24 hours to 60 seconds,
     though the interval is now configurable using a setting.
     An additional check for conflicts is added after interactive
     check-in comment entry, to compensate for the reduced lock interval.
  *  Performance optimizations.
  *  Many documentation improvements.
Changes to www/checkin_names.wiki.
1
2
3
4
5
6
7
8
9

10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
<title>Check-in Names</title>

<table align="right" border="1" width="33%" cellpadding="10">
<tr><td>
<h3>Executive Summary</h3>
<p>A check-in can be identified using any of the following
names:
<ul>
<li> Cryptographic hash prefix

<li> Tag or branchname
<li> Timestamp:  <i>YYYY-MM-DD HH:MM:SS</i>
<li> <i>tag-name</i> <big><b>:</b></big> <i>timestamp</i>
<li> <b>root :</b> <i>branchname</i>

<li> Special names:
<ul>
<li> <b>tip</b>
<li> <b>current</b>
<li> <b>next</b>
<li> <b>previous</b> or <b>prev</b>
<li> <b>ckout</b> for embedded docs
</ul>
</ul>
</td></tr>
</table>
Many Fossil [/help|commands] and [./webui.wiki | web-interface] URLs accept
check-in names as an argument.  For example, the "[/help/info|info]" command
accepts an optional check-in name to identify the specific checkout




|
<
<

|
>
|



>






|







1
2
3
4
5


6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<title>Check-in Names</title>

<table align="right" border="1" width="33%" cellpadding="10">
<tr><td>
<h3>Quick Reference</h3>


<ul>
<li> Hash prefix
<li> Branch name
<li> Tag name
<li> Timestamp:  <i>YYYY-MM-DD HH:MM:SS</i>
<li> <i>tag-name</i> <big><b>:</b></big> <i>timestamp</i>
<li> <b>root :</b> <i>branchname</i>
<li> <b>merge-in :</b> <i>branchname</i>
<li> Special names:
<ul>
<li> <b>tip</b>
<li> <b>current</b>
<li> <b>next</b>
<li> <b>previous</b> or <b>prev</b>
<li> <b>ckout</b> (<a href='./embeddeddocs.wiki'>embedded docs</a> only)
</ul>
</ul>
</td></tr>
</table>
Many Fossil [/help|commands] and [./webui.wiki | web-interface] URLs accept
check-in names as an argument.  For example, the "[/help/info|info]" command
accepts an optional check-in name to identify the specific checkout
Added www/css-tricks.md.






















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# Fossil CSS Tips and Tricks

Many aspects of Fossil's appearance can be customized by
[customizing the site skin](customskin.md). This document
details certain specific CSS tweaks which users have asked
about via the forums.

This is a "living document" - please feel free to suggest
additions via [the Fossil forum](https://fossil-scm.org/forum/).

This document is *not* an introduction to CSS - the web is
full of tutorials on that topic. It covers only the specifics
of customizing certain CSS-based behaviors in a Fossil UI. That said...

# Overriding Default Rules

One behavior of the skinning system works considerably differently
from the cascading nature of CSS: if a skin applies a CSS selector for
which Fossil has a built-in default value, Fossil elides the entire
default definition for that rule. i.e., the skin's definition is the
only one which is applied, rather than cascading the definition from
the default value.

For example, if Fossil has a default CSS rule which looks like:

```css
div.foo {
  font-size: 120%;
  margin-left: 1em;
}
```

And a skin has:

```css
div.foo {}
```

Then Fossil will *not* emit its default rule and the user's copy will
become the only definition of that CSS rule. This is different from
normal CSS cascading rules, in which the above sequence would result
in, effectively, the top set of rules being applied because the second
(empty) one does not override anything from the first.

If a skin applies a given selector more than once, or imports external
style sheets which do, those cascade following CSS's normal rules.

## Is it Really `!important`?

By and large, CSS's `!important` qualifier is not needed when
customzing Fossil's CSS. On occasion, however, particular styles may
be set directly on DOM elements when Fossil generates its HTML, and
such cases require the use of `!important` to override them.


<!-- ============================================================ -->
# Main UI CSS

## Number of Columns in `/dir` View

The width of columns on the [`/dir` page](/dir) is calculated
dynamically as the page is generated, to attempt to fit the widest
name in a given directory. The number of columns is determined
automatically by CSS. To modify the number of columns and/or the entry width:

```css
div.columns {
  columns: WIDTH COLUMN_COUNT !important;
  /* Examples:
    columns: 20ex 3 !important
    columns: auto auto !important
  */
}
/* The default rule uses div.columns, but it can also be selected using: */
div.columns.files { ... }
```

The `!important` qualifier is required here because the style values are dynamically
calculated and applied when the HTML is emitted.

The file list itself can be further customized via:

```css
div.columns > ul {
 ...
}
ul.browser {
 ...
}
```


<!-- ============================================================ -->
# Forum-specific CSS

## Limiting Display Length of Long Posts

Excessively long posts can make scrolling through threads problematic,
especially on mobile devices. The amount of a post which is visible can
be configured using:

```css
div.forumPostBody {
  max-height: 25em; /* change to the preferred maximum effective height */
  overflow: auto; /* tells the browser to add scrollbars as needed */
}
```
Changes to www/customskin.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

60
61



62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102























































































































































































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

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# Skinning the Fossil Web Interface

Every HTML page generated by Fossil has the following basic structure:

<blockquote><table border=1 cellpadding=10><tbody>
<tr><td style='background-color:lightblue;text-align:center;'>Header</td></tr>
<tr><td style='background-color:lightgreen;text-align:center;'>
Fossil-Generated Content</td></tr>
<tr><td style='background-color:lightblue;text-align:center;'>Footer</td></tr>
<tr><td style='background-color:lightyellow;text-align:center;'>Javascript (optional)</td></tr>
</tbody></table></blockquote>

The default header looks something like this:

        <div class="header">
          <div class="title"><h1>$<project_name></h1>$<title></div>
          ... top banner and menu bar ...

The Fossil-generated content section looks like this:

        <div class="content">
          ... generated content here ...
        </div>

And the footer looks like this:

        <div class="footer">
          ... skin-specific stuff here ...
        </div>
        <script nonce=$nonce>
          <th1>styleScript</th1>
        </script>

Notice that there are no `<html>` or `<head>` elements in the header,
nor is there an `</html>` closing tag in the footer.  Fossil generates
this material automatically unless it sees that you have provided your
own HTML document header within the skin’s Header section.

This design lets most users get the benefit of Fossil’s automatic HTML
document header, which takes care of quite a few different things for
you, while still allowing you to [override if at need](#headfoot).

When overriding the default document header, you might want to use some
of the [TH1 variables documented below](#vars) such as `$stylesheet_url`
to avoid hand-writing code that Fossil can generate for you.

The middle "content" section comprises the bulk of most pages and
contains the actual Fossil-generated data
that the user is interested in seeing.  The text of this content
section is not normally configurable.  The content text can be styled
using CSS, but it is otherwise fixed.  Hence it is the header, the footer,
and the CSS that determine the look of a repository.
We call the bundle of built-in CSS, header, and footer a "skin".


## <a name="builtin"></a>Built-in Skins

Fossil comes with several built-in skins.  The sources to these built-ins can
be found in the Fossil source tree under the skins/ folder.  The skins/

folder contains a separate subfolder for each built-in skin, with each
subfolders holding four files, "css.txt", "details.txt",



"footer.txt", and "header.txt",
that describe the CSS, rendering options,
footer, and header for that skin, respectively.


The skin of a repository can be changed to any of the built-in skins using
the web interface by going to the /setup_skin web page (requires Admin
privileges) and clicking the appropriate button.  Or, the --skin command
line option can be used for the
[fossil ui](../../../help?cmd=ui) or
[fossil server](../../../help?cmd=server) commands to force that particular
instance of Fossil to use the specified built-in skin.


## <a name="sharing"></a>Sharing Skins

The skin of a repository is not part of the versioned state and does not
"push" or "pull" like checked-in files.  The skin is local to the
repository.  However, skins can be shared between repositories using
the [fossil config](../../../help?cmd=configuration) command.
The "fossil config push skin" command will send the local skin to a remote
repository and the "fossil config pull skin" command will import a skin
from a remote repository.  The "fossil config export skin FILENAME"
will export the skin for a repository into a file FILENAME.  This file
can then be imported into a different repository using the
"fossil config import FILENAME" command.  Unlike "push" and "pull",
the "export" and "import" commands are able to move skins between
repositories for different projects.  So, for example, if you have a
group of related repositories, you can develop a skin for one of them,
then get a consistent look across all the repositories by exporting
the skin from the first repository and importing into all the others.

The file generated by "fossil config export" could be checked into
one of your repositories and versioned, if desired.  This will not
automatically change the skin when looking backwards in time, but it
will provide an historical record of what the skin used to be and
allow the historical look of the repositories to be recreated if
necessary.

When cloning a repository, the skin of new repository is initialized to
the skin of the repository from which it was cloned.

























































































































































































## <a name="headfoot"></a>Header and Footer Processing

The `header.txt` and `footer.txt` files of a skin are merely the HTML text
of the header and footer, except that before being prepended and appended to
the content, their text content is run through a
[TH1 interpreter](./th1.md) that might adjust the text as follows:

  *  All text within &lt;th1&gt;...&lt;/th1&gt; is elided from the
     output and that text is instead run as a TH1 script.  That TH1
     script has the opportunity to insert new text in place of itself,
     or to inhibit or enable the output of subsequent text.

  *  Text of the form "$NAME" or "$&lt;NAME&gt;" is replaced with
     the value of the TH1 variable NAME.

Above, we saw the first few lines of a typical Fossil skin header:


        <div class="header">
          <div class="title"><h1>$<project_name></h1>$<title>/div>

After variables are substituted by TH1, that will look more like this:

        <div class="header">
          <div class="title"><h1>Project Name</h1>Page Title</div>

As you can see, two TH1 variable substitutions were done.

The same TH1 interpreter is used for both the header and the footer
and for all scripts contained within them both.  Hence, any global
TH1 variables that are set by the header are available to the footer.

Fossil provides the HTML
document container tags `<html>`, `<head>`, and their inner content when
your skin’s header and footer don’t include them. This default header
declares the repository’s Content Security Policy (CSP) which is well
worth understanding, but since it is not strictly about skinning, we
cover that in [a separate document](./defcsp.md).


## <a name="menu"></a>Customizing the ≡ Hamburger Menu

The menu bar of the default skin has an entry to open a drop-down menu with
additional navigation links, represented by the ≡ button (hence the name
"hamburger menu"). The Javascript logic to open and close the hamburger menu
when the button is clicked is contained in the optional Javascript part (js.txt)


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

<
<
<
|
<

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

<
<
<
|
|
>

|
>
>
>
|
<
|
>

|
<
<
<
<
<
<
|






|



















|


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



|
|
|


|
|






|
>














<
<
<
<
<
<
<
<







1
2

3







4

5



6

7



8

9






10




11



12



13







14



15
16
17
18
19
20
21
22
23

24
25
26
27






28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272








273
274
275
276
277
278
279
# Skinning the Fossil Web Interface


The Fossil web interface comes with a pre-configured look and feel.  The default







look and feel works fine in many situations.  However, you may want to change

the look and feel (the "skin") of Fossil to better suite your own individual tastes.



This document provides background information to aid you in that task.





## <a name="builtin"></a>Built-in Skins








Fossil comes with multiple built-in skins.  If the default skin does not




suite your tastes, perhaps one of the other built-in skins will work better.



If nothing else, the built-in skins can serve as examples or baselines that



you can use to develop your own custom skin.











The sources to these built-ins can
be found in the Fossil source tree under the skins/ folder.  The 
[skins/](/dir?ci=trunk&name=skins)
folder contains a separate subfolder for each built-in skin, with each
subfolders holding at least these five files:

   * css.txt
   * details.txt
   * footer.txt

   * header.txt
   * js.txt

Try out the built-in skins by using the --skin option on the






[fossil ui](/help?cmd=ui) or [fossil server](/help?cmd=server) commands.

## <a name="sharing"></a>Sharing Skins

The skin of a repository is not part of the versioned state and does not
"push" or "pull" like checked-in files.  The skin is local to the
repository.  However, skins can be shared between repositories using
the [fossil config](/help?cmd=configuration) command.
The "fossil config push skin" command will send the local skin to a remote
repository and the "fossil config pull skin" command will import a skin
from a remote repository.  The "fossil config export skin FILENAME"
will export the skin for a repository into a file FILENAME.  This file
can then be imported into a different repository using the
"fossil config import FILENAME" command.  Unlike "push" and "pull",
the "export" and "import" commands are able to move skins between
repositories for different projects.  So, for example, if you have a
group of related repositories, you can develop a skin for one of them,
then get a consistent look across all the repositories by exporting
the skin from the first repository and importing into all the others.

The file generated by "fossil config export" could be checked into
one of your repositories and versioned, if desired.  This will not
automatically change the skin when looking backwards in time, but it
will provide an historical record of what the skin used to be and
allow the historical look of the repositories to be recreated if
necessary.

When cloning a repository, the skin of the new repository is initialized to
the skin of the repository from which it was cloned.

# Structure Of A Fossil Web Page

Every HTML page generated by Fossil has the same basic structure:

<blockquote><table border=1 cellpadding=10><tbody>
<tr><td style='background-color:lightgreen;text-align:center;'>
Fossil-Generated HTML Header</td></tr>
<tr><td style='background-color:lightblue;text-align:center;'>Content Header</td></tr>
<tr><td style='background-color:lightgreen;text-align:center;'>
Fossil-Generated Content</td></tr>
<tr><td style='background-color:lightblue;text-align:center;'>Content Footer</td></tr>
<tr><td style='background-color:lightgreen;text-align:center;'>
Fossil-Generated HTML Footer</td></tr>
</tbody></table></blockquote>

The green parts are generated by Fossil.  The blue parts are things that
you, the administrator, get to modify in order to customize the skin.

Fossil *usually* (but not always - [see below](#override))
generates the initial HTML Header section of a page.  The
generated HTML Header will look something like this:

         <html>
         <head>
         <base href="..." />
         <meta http-equiv="Content-Security-Policy" content="...." />
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <title>....</title>
         <link rel="stylesheet" href="..." type="text/css" />
         </head>
         <body>

In most cases, it is best to leave the Fossil-generated HTML Header alone.
The configurable part of the skin begins with the Content Header section which
should followign the following template:

        <div class="header">
          ... top banner and menu bar ...
        </div>

Note that `<div class="header">` and `</div>` tags must be included in the
Content Header text of the skin.  In other words, you the administrator need
to supply that text as part of your skin customization.

The Fossil-generated Content section immediately follows the Content Header.
The Content section will looks like this:

        <div class="content">
          ... Fossil-generated content here ...
        </div>

After the Content is the custom Content Footer section which should
following this template:

        <div class="footer">
          ... skin-specific stuff here ...
        </div>
        <script nonce="$nonce">
          <th1>styleScript</th1>
        </script>

As with the Content Header, the template elements of the Content Footer
should appear exactly as they are shown.

Finally, Fossil always adds its own footer (unless overridden)
to close out the generated HTML:

        </body>
        </html>

## <a name="override"></a>Overriding the HTML Header and Footer

Notice that the `<html>`, `<head>`, and opening `<body>` 
elements at the beginning of the document,
and the closing `</body>` and `</html>` elements at the end are automatically
generated by Fossil.  This is recommended.

However, for maximum design flexibility, Fossil allows those elements to be
supplied as part of the configurable Content Header and Content Footer.
If the Content Header contains the text "`<body`", then Fossil assumes that
the Content Header and Content Footer will handle all of the `<html>`,
`<head>`, and `<body>` text itself, and the Fossil-generated header and
footer will be blank.

When overriding the HTML Header in this way, you will probably want to use some
of the [TH1 variables documented below](#vars) such as `$stylesheet_url`
to avoid hand-writing code that Fossil can generate for you.

# Designing, Debugging, and Installing A Custom Skin

It is possible to develop a new skin from scratch.  But a better and easier
approach is to use one of the existing built-in skins as a baseline and
make incremental modifications, testing after each step, to obtain the
desired result.

The skin is controlled by five files:

<blockquote><dl>
<dt><b>css.txt</b></dt><dd>

<p>The css.txt file is the text of the CSS for Fossil.
Fossil might add additional CSS elements after the
the css.txt file, if it sees that the css.txt omits some
CSS components that Fossil needs.  But for the most part,
the content of the css.txt is the CSS for the page.</dd>

<dt><b>details.txt</b><dt><dd>

<p>The details.txt file is short list of settings that control
the look and feel, mostly of the timeline.  The default
details.txt file looks like this:

<blockquote><pre>
timeline-arrowheads:        1
timeline-circle-nodes:      1
timeline-color-graph-lines: 1
white-foreground:           0
</pre></blockquote>

The first three setings in details.txt control the appearance
of certain aspects of the timeline graph.  The number on the
right is a boolean - "1" to activate the feature and "0" to
disable it.  The "white-foreground:" setting should be set to
"1" if the page color has light-color text on a darker background,
and "0" if the page has dark text on a light-colored background.</dd>

<dt><b>footer.txt</b> and <b>header.txt</b></dt><dd>

<p>The footer.txt and header.txt files contain the Content Footer
and Content Header respectively.  Of these, the Content Header is
the most important, as it contains the markup used to generate
the banner and menu bar for each page.

<p>Both the footer.txt and header.txt file are 
[processed using TH1](#headfoot) prior to being output as 
part of the overall web page.</dd>

<dt><b>js.txt</b></dt><dd>

<p>The js.txt file is intended to be javascript.  The complete
text of this javascript is typically inserted into the Content Footer
by this part of the "footer.txt" file:

<blockquote><pre>
&lt;script nonce="$nonce"&gt;
  &lt;th1&gt;styleScript&lt;/th1&gt;
&lt;/script&gt;
</pre></blockquote>

<p>The js.txt file was originally intended to insert javascript
that controls the hamburger menu.
The footer.txt file probably should contain lines like the
above, even if js.txt is empty.</dd>
</dl></blockquote>

Developing a new skin is simply a matter of creating appropriate
versions of these five control files.

### Skin Development Using The Web Interface

Users with admin privileges can use the Admin/Skin configuration page
on the web interface to develop a new skin.  The development of a new
skin occurs without disrupting the existing skin.  So you can work on
a new skin for a Fossil instance while the existing skin is still in
active use.

The new skin is a "draft" skin.  You initialize one of 9 draft skins
to either the current skin or to one of the built-in skins.  Then
use forms to edit the 5 control files described above.  The new
skin can be tested after each edit.  Finally, once the new skin is
working as desired, the draft skin is "published" and becomes the
new live skin that most users see.

### Skin Development Using A Local Text Editor

An alternative approach is to copy the five control files for your
baseline skin into a temporary working directory (here called
"./newskin") and then launch the [fossil ui](/help?cmd=ui) command
with the "--skin ./newskin" option.  If the argument to the --skin
option contains a "/" character, then the five control files are
read out of the directory named.  You can then edit the control
files in the ./newskin folder using you favorite text editor, and
press "Reload" on your browser to see the effects.

## <a name="headfoot"></a>Header and Footer Processing

The `header.txt` and `footer.txt` control files of a skin are the HTML text
of the Contnet Header and Content Footer, except that before being inserted
into the output stream, the text is run through a
[TH1 interpreter](./th1.md) that might adjust the text as follows:

  *  All text within &lt;th1&gt;...&lt;/th1&gt; is omitted from the
     output and is instead run as a TH1 script.  That TH1
     script has the opportunity to insert new text in place of itself,
     or to inhibit or enable the output of subsequent text.

  *  Text of the form "$NAME" or "$&lt;NAME&gt;" is replaced with
     the value of the TH1 variable NAME.

For example, first few lines of a typical Content Header will look
like this:

        <div class="header">
          <div class="title"><h1>$<project_name></h1>$<title>/div>

After variables are substituted by TH1, that will look more like this:

        <div class="header">
          <div class="title"><h1>Project Name</h1>Page Title</div>

As you can see, two TH1 variable substitutions were done.

The same TH1 interpreter is used for both the header and the footer
and for all scripts contained within them both.  Hence, any global
TH1 variables that are set by the header are available to the footer.









## <a name="menu"></a>Customizing the ≡ Hamburger Menu

The menu bar of the default skin has an entry to open a drop-down menu with
additional navigation links, represented by the ≡ button (hence the name
"hamburger menu"). The Javascript logic to open and close the hamburger menu
when the button is clicked is contained in the optional Javascript part (js.txt)
Changes to www/defcsp.md.
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
override the default CSP by giving this variable a value before Fossil
sees that it’s undefined and uses this default.

The best place to do that is from the [`th1-setup`
script](./th1-hooks.md), which runs before TH1 processing happens during
skin processing:

        $ fossil set th1-setup "set default_csp {default-src: 'self'}"

This is the cleanest method, allowing you to set a custom CSP without
recompiling Fossil or providing a hand-written `<head>` section in the
Header section of a custom skin.

You can’t remove the CSP entirely with this method, but you can get the
same effect by telling the browser there are no content restrictions:

        $ fossil set th1-setup 'set default_csp {default-src: *}'


### <a name="header"></a>Custom Skin Header

Fossil only inserts a CSP into the HTML pages it generates when the
[skin’s Header section](./customskin.md#headfoot) doesn’t contain a
`<head>` tag. None of the stock skins include a `<head>` tag,² so if you







|








|







317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
override the default CSP by giving this variable a value before Fossil
sees that it’s undefined and uses this default.

The best place to do that is from the [`th1-setup`
script](./th1-hooks.md), which runs before TH1 processing happens during
skin processing:

        $ fossil set th1-setup "set default_csp {default-src 'self'}"

This is the cleanest method, allowing you to set a custom CSP without
recompiling Fossil or providing a hand-written `<head>` section in the
Header section of a custom skin.

You can’t remove the CSP entirely with this method, but you can get the
same effect by telling the browser there are no content restrictions:

        $ fossil set th1-setup 'set default_csp {default-src *}'


### <a name="header"></a>Custom Skin Header

Fossil only inserts a CSP into the HTML pages it generates when the
[skin’s Header section](./customskin.md#headfoot) doesn’t contain a
`<head>` tag. None of the stock skins include a `<head>` tag,² so if you
Changes to www/embeddeddoc.wiki.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

60
61
62
63
64
65
66
67
68
  3.  Only people with check-in privileges can modify the documentation.
      (This might be either an advantage or disadvantage, depending
      on the nature of your project.)

We will call documentation that is included as files in the source tree
"embedded documentation".

<h2>Fossil Support For Embedded Documentation</h2>

The fossil web interface supports embedded documentation using
the "/doc" page.  To access embedded documentation, one points
a web browser to a fossil URL of the following form:

<blockquote>
<i>&lt;baseurl&gt;</i><big><b>/doc/</b></big><i>&lt;version&gt;</i><big><b>/</b></big><i>&lt;filename&gt;</i>
</blockquote>

The <i>&lt;baseurl&gt;</i> is the main URL used to access the fossil web server.
For example, the <i>&lt;baseurl&gt;</i> for the fossil project itself is
either <b>http://www.fossil-scm.org/fossil</b> or
<b>http://www.hwaci.com/cgi-bin/fossil</b>.
If you launch the web server using the "<b>fossil server</b>" command line,
then the <i>&lt;baseurl&gt;</i> is usually
<b>http://localhost:8080/</b>.

The <i>&lt;version&gt;</i> is any unique prefix of the check-in ID for
the check-in containing the documentation you want to access.
Or <i>&lt;version&gt;</i> can be the name of a
[./branching.wiki | branch] in order to show
the documentation for the latest version of that branch.
Or <i>&lt;version&gt;</i> can be one of the keywords "<b>tip</b>" or
"<b>ckout</b>".  The "<b>tip</b>" keyword means to use the most recent
check-in.  This is useful if you want to see the very latest
version of the documentation.  The "<b>ckout</b>" keywords means to
pull the documentation file from the local source tree on disk, not
from the any check-in.  The "<b>ckout</b>" keyword normally
only works when you start your server using the "<b>fossil server</b>"
or "<b>fossil ui</b>"

command line and is intended to show what the documentation you are currently
editing looks like before you check it in.

Finally, the <i>&lt;filename&gt;</i> element of the URL is the
pathname of the documentation file relative to the root of the source
tree.

The mimetype (and thus the rendering) of documentation files is
determined by the file suffix.  Fossil currently understands







|











|
<
|



|
|
|
<
|
|
|
<
|

|
|
|
>
|
<







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

42
43
44
45
46
47
48

49
50
51

52
53
54
55
56
57
58

59
60
61
62
63
64
65
  3.  Only people with check-in privileges can modify the documentation.
      (This might be either an advantage or disadvantage, depending
      on the nature of your project.)

We will call documentation that is included as files in the source tree
"embedded documentation".

<h1>1.0 Fossil Support For Embedded Documentation</h1>

The fossil web interface supports embedded documentation using
the "/doc" page.  To access embedded documentation, one points
a web browser to a fossil URL of the following form:

<blockquote>
<i>&lt;baseurl&gt;</i><big><b>/doc/</b></big><i>&lt;version&gt;</i><big><b>/</b></big><i>&lt;filename&gt;</i>
</blockquote>

The <i>&lt;baseurl&gt;</i> is the main URL used to access the fossil web server.
For example, the <i>&lt;baseurl&gt;</i> for the fossil project itself is
[https://www.fossil-scm.org/fossil].

If you launch the web server using the "[/help?cmd=ui|fossil ui]" command line,
then the <i>&lt;baseurl&gt;</i> is usually
<b>http://localhost:8080/</b>.

The <i>&lt;version&gt;</i> is [./checkin_names.wiki|name of a check-in]
that contains the embedded document.  This might be a hash prefix for
the check-in, or it might be the name of a branch or tag, or it might

be a timestamp.  See the [./checkin_names.wiki|check-in name documentation]
for more possibilities and examples.  The <i>&lt;version&gt;</i> can
also be the special identifier "<b>ckout</b>".

The "<b>ckout</b>" keywords means to
pull the documentation file from the local source tree on disk, not
from the any check-in.  The "<b>ckout</b>" keyword
only works when you start your server using the 
"[/help?cmd=server|fossil server]" or "[/help?cmd=ui|fossil ui]"
commands.  The "/doc/ckout" URL is intended to show a preview of
the documentation you are currently editing but have not yet you checked in.


Finally, the <i>&lt;filename&gt;</i> element of the URL is the
pathname of the documentation file relative to the root of the source
tree.

The mimetype (and thus the rendering) of documentation files is
determined by the file suffix.  Fossil currently understands
77
78
79
80
81
82
83


84
85
86
87
88
89
90
91
92
93
94
95
96
97


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

116
117
118
119


120
121
122
123
124

125
126
127
128

129
130


131




132

133




134



135







136
137
138
139
140
141
142







143

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
Documentation files ending in ".md" or ".markdown" use the
[/md_rules  | Markdown markup language].
Documentation files ending in ".txt" are plain text.
Wiki, markdown, and plain text documentation files
are rendered with the standard fossil header and footer added.
Most other mimetypes are delivered directly to the requesting
web browser without interpretation, additions, or changes.



<a name="html"></a>Files with the mimetype "text/html" (the .html or .htm suffix) are
usually rendered directly to the browser without interpretation.
However, if the file begins with a &lt;div&gt; element like this:

    <b>&lt;div class='fossil-doc' data-title='<i>Title Text</i>'&gt;</b>

Then the standard Fossil header and footer are added to the document
prior to being displayed.  The "class='fossil-doc'" attribute is
required for this to occur.  The "data-title='...'" attribute is
optional, but if it is present the text will become the title displayed
in the Fossil header.  An example of this can be seen in the text
of the [/artifact/84b4b3d041d93a?txt=1 | Index Of Fossil Documentation]
document.



Beware that such HTML files render in the same browser security context
as all other embedded documentation served from Fossil; they are not
fully-independent web pages. One practical consequence of this is that
embedded <tt>&lt;script&gt;</tt> tags will cause a
[https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP | Content
Security Policy] error in your browser with the default CSP as served by
Fossil. See the documentation on [./customskin.md#headfoot | Header and
Footer Processing] and [./defcsp.md | The Default CSP].


<h2>Server-Side Text Substitution</h2>

Fossil can do a few types of substitution of server-side information
into the embedded document.

<h3>1. $ROOT</h3>


To allow for repositories [./server/ | served deeper than the root of the
URL hierarchy], Fossil can substitute the repository's root in the URL
scheme into HTML <tt>href</tt> and <tt>action</tt> attributes. For
example:



<nowiki><pre>
        [$ROOT/doc.wiki | doc at project root]
</pre></nowiki>


might become this in the rendered HTML:

<nowiki><pre>
        &lt;a href="/project/root/doc.wiki"&gt;doc at project root&lt;/a&gt;

</pre></nowiki>



As you can see, this happens for all source document types that end up




rendering as HTML, not just source documents in the HTML

<tt>fossil-doc</tt> format described at the end of the prior section.
















<h3 id="th1">2. TH1 Documents</h3>

Fossil will substitute the value of [./th1.md | TH1 expressions] within
<tt>{</tt> curly braces <tt>}</tt> into the output HTML if you have
configured it with the <tt>--with-th1-docs</tt> option, which is
disabled by default.










<h2>Examples</h2>

This file that you are currently reading is an example of
embedded documentation.  The name of this file in the fossil
source tree is "<b>www/embeddeddoc.wiki</b>".
You are perhaps looking at this
file using the URL:

   [http://www.fossil-scm.org/index.html/doc/trunk/www/embeddeddoc.wiki].

The first part of this path, the "[http://www.fossil-scm.org/index.html]",
is the base URL.  You might have originally typed:
[http://www.fossil-scm.org/].  The web server at the www.fossil-scm.org
site automatically redirects such links by appending "index.html".  The
"index.html" file on www.fossil-scm.org is really a CGI script
(do not be mislead by the name) which runs the fossil web service in
CGI mode.  The "index.html" CGI script looks like this:

<blockquote><pre>
#!/usr/bin/fossil
repository: /fossil/fossil.fossil
</pre></blockquote>

This is one of the many ways to set up a







>
>











|
|
|
>
>











|




|

>
|
<
<
|
>
>


|


>
|


|
>


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

>
>
>

>
>
>
>
>
>
>
|






>
>
>
>
>
>
>

>
|







|

|


|
|
|
|







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
Documentation files ending in ".md" or ".markdown" use the
[/md_rules  | Markdown markup language].
Documentation files ending in ".txt" are plain text.
Wiki, markdown, and plain text documentation files
are rendered with the standard fossil header and footer added.
Most other mimetypes are delivered directly to the requesting
web browser without interpretation, additions, or changes.

<h2>1.1 HTML Rendering With Fossil Headers And Footers</h2>

<a name="html"></a>Files with the mimetype "text/html" (the .html or .htm suffix) are
usually rendered directly to the browser without interpretation.
However, if the file begins with a &lt;div&gt; element like this:

    <b>&lt;div class='fossil-doc' data-title='<i>Title Text</i>'&gt;</b>

Then the standard Fossil header and footer are added to the document
prior to being displayed.  The "class='fossil-doc'" attribute is
required for this to occur.  The "data-title='...'" attribute is
optional, but if it is present the text will become the title displayed
in the Fossil header.  An example of this can be seen in Fossil
Documentation Index www/permutedindex.html:

  *  [/file/www/permutedindex.html?txt|source text for <b>www/permutedindex.html</b>]
  *  [/doc/trunk/www/permutedindex.html|<b>www/permutedindex.html</b> rendered as HTML]

Beware that such HTML files render in the same browser security context
as all other embedded documentation served from Fossil; they are not
fully-independent web pages. One practical consequence of this is that
embedded <tt>&lt;script&gt;</tt> tags will cause a
[https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP | Content
Security Policy] error in your browser with the default CSP as served by
Fossil. See the documentation on [./customskin.md#headfoot | Header and
Footer Processing] and [./defcsp.md | The Default CSP].


<h1>2.0 Server-Side Text Substitution</h1>

Fossil can do a few types of substitution of server-side information
into the embedded document.

<h2>2.1 "$ROOT" In HTML and Markdown Hyperlinks</h2>

Hyperlinks in Markdown and HTML embedded documents can reference 
the root of the Fossil repository using the special text "$ROOT"


at the beginning of a URL. For example, a Markdown hyperlink to
the Markdown formatting rules might be
written in the embedded document like this:

<nowiki><pre>
        [Markdown formatting rules]($ROOT/wiki_rules)
</pre></nowiki>

Depending on how the how the Fossil server is configured, that hyperlink
might be renderer like one of the following:

<nowiki><pre>
        &lt;a href="/wiki_rules"&gt;Wiki formatting rules&lt;/a&gt;
        &lt;a href="/cgi-bin/fossil/wiki_rules"&gt;Wiki formatting rules&lt;/a&gt;
</pre></nowiki>

So, in other words, the "$ROOT" text is converted into whatever
the "&lt;baseurl&gt;" is for the document.

This substitution works for HTML and Markdown documents.
It does not work for Wiki embedded documents, since with
Wiki you can just begin a URL with "/" and it automatically knows
to prepend the $ROOT.

<h2>2.2 "$CURRENT" In "/doc/" Hyperlinks</h2>

Similarly, URLs of the form "/doc/$CURRENT/..." have the check-in
hash of the check-in currently being viewed substituted in place of
the "$CURRENT" text.  This feature, in combination with the "$ROOT"
substitution above, allows an absolute path to be used for hyperlinks.

For example, if an embedded document documented wanted to reference
some other document in a separate file named "www/otherdoc.md",
it could use a URL like this:

<nowiki><pre>
        [Other Document]($ROOT/doc/$CURRENT/www/otherdoc.md)
</pre></nowiki>

As with "$ROOT", this substitution only works for Markdown and HTML
documents.  For Wiki documents, you would need to use a relative URL.

<h2 id="th1">2.3 TH1 Documents</h2>

Fossil will substitute the value of [./th1.md | TH1 expressions] within
<tt>{</tt> curly braces <tt>}</tt> into the output HTML if you have
configured it with the <tt>--with-th1-docs</tt> option, which is
disabled by default.

Since TH1 is a full scripting language, this feature essential grants
the ability to execute code on the server to any with check-in 
privilege for the project.
This is a security risk that needs to be carefully managed.
The feature is off by default.
Administrators should understand and carefully assess the risks
before enabling the use of TH1 within embedded documentation.


<h1>3.0 Examples</h1>

This file that you are currently reading is an example of
embedded documentation.  The name of this file in the fossil
source tree is "<b>www/embeddeddoc.wiki</b>".
You are perhaps looking at this
file using the URL:

   [http://www.fossil-scm.org/fossil/doc/trunk/www/embeddeddoc.wiki].

The first part of this path, the "[http://www.fossil-scm.org/fossil]",
is the base URL.  You might have originally typed:
[http://www.fossil-scm.org/].  The web server at the www.fossil-scm.org
site automatically redirects such links by appending "fossil".  The
"fossil" file on www.fossil-scm.org is really a CGI script
which runs the fossil web service in CGI mode.
The "fossil" CGI script looks like this:

<blockquote><pre>
#!/usr/bin/fossil
repository: /fossil/fossil.fossil
</pre></blockquote>

This is one of the many ways to set up a
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

When the symbolic name is a date and time, fossil shows the version
of the document that was most recently checked in as of the date
and time specified.  So, for example, to see what the fossil website
looked like at the beginning of 2010, enter:

<blockquote>
<a href="http://www.fossil-scm.org/index.html/doc/2010-01-01/www/index.wiki">
http://www.fossil-scm.org/index.html/doc/<b>2010-01-01</b>/www/index.wiki
</a>
</blockquote>

The file that encodes this document is stored in the fossil source tree under
the name "<b>www/embeddeddoc.wiki</b>" and so that name forms the
last part of the URL for this document.








|
|







220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

When the symbolic name is a date and time, fossil shows the version
of the document that was most recently checked in as of the date
and time specified.  So, for example, to see what the fossil website
looked like at the beginning of 2010, enter:

<blockquote>
<a href="http://www.fossil-scm.org/fossil/doc/2010-01-01/www/index.wiki">
http://www.fossil-scm.org/fossil/doc/<b>2010-01-01</b>/www/index.wiki
</a>
</blockquote>

The file that encodes this document is stored in the fossil source tree under
the name "<b>www/embeddeddoc.wiki</b>" and so that name forms the
last part of the URL for this document.

Changes to www/env-opts.md.
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

`--vfs VFSNAME`: Load the named VFS into SQLite.


Environment Variables
---------------------

On most platforms, the location of the users account-wide `.fossil`
file is either `FOSSIL_HOME` or `HOME`, in that order. This ordering
lets you put this file somewhere other than at the top of your user’s
home directory by defining `FOSSIL_HOME` to mask the always-defined
`HOME`.

For native Windows builds and for Cygwin builds, the file is called
`_fossil` instead to avoid problems with old programs that assume file
names cannot begin with a dot, as was true in old versions of Windows
and in MS-DOS. (Newer Microsoft OSes and file systems don’t have a
problem with such files, but still we take the safe path in case you’re
on a system with software that can’t cope.) We start our search with
`FOSSIL_HOME` again, but instead of falling back to `HOME`, we instead
try `USERPROFILE`, then `LOCALAPPDATA`, then `APPDATA`, and finally we
concatenate `HOMEDRIVE` + `HOMEPATH`.

`EDITOR`: Name the editor to use for check-in and stash comments.
Overridden by the local or global `editor` setting or the `VISUAL`
environment variable.

`FOSSIL_BREAK`: If set, an opportunity will be created to attach a
debugger to the Fossil process prior to any significant work being







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







110
111
112
113
114
115
116
117
118
119


120









121
122
123
124
125
126
127

`--vfs VFSNAME`: Load the named VFS into SQLite.


Environment Variables
---------------------

The location of the user's account-wide [configuration database][configdb]
depends on the operating system and on the existance of various 
environment variables and/or files.  See the discussion of the


[configuration database location algorithm][configloc] for details.










`EDITOR`: Name the editor to use for check-in and stash comments.
Overridden by the local or global `editor` setting or the `VISUAL`
environment variable.

`FOSSIL_BREAK`: If set, an opportunity will be created to attach a
debugger to the Fossil process prior to any significant work being
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
`FOSSIL_FORCE_WIKI_MODERATION`: If set, *ALL* changes for wiki pages
will be required to go through moderation (even those performed by the
local interactive user via the command line).  This can be useful for
local (or remote) testing of the moderation subsystem and its impact
on the contents and status of wiki pages.


`FOSSIL_HOME`: Location of the `~/.fossil` file. The first environment
variable found in the environment from the list `FOSSIL_HOME`,
`LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and
`HOMEPATH` (Windows, used together), and `HOME` is used as the
location of the `~/.fossil` file.


`FOSSIL_USE_SEE_TEXTKEY`: If set, treat the encryption key string for
SEE as text to be hashed into the actual encryption key.  This has no
effect if Fossil was not compiled with SEE support enabled.


`FOSSIL_USER`: Name of the default user account if the checkout, local







|
<
<
<
|
|







136
137
138
139
140
141
142
143



144
145
146
147
148
149
150
151
152
`FOSSIL_FORCE_WIKI_MODERATION`: If set, *ALL* changes for wiki pages
will be required to go through moderation (even those performed by the
local interactive user via the command line).  This can be useful for
local (or remote) testing of the moderation subsystem and its impact
on the contents and status of wiki pages.


`FOSSIL_HOME`: Location of [configuration database][configdb].



See the [configuration database location][configloc] description
for additional information.

`FOSSIL_USE_SEE_TEXTKEY`: If set, treat the encryption key string for
SEE as text to be hashed into the actual encryption key.  This has no
effect if Fossil was not compiled with SEE support enabled.


`FOSSIL_USER`: Name of the default user account if the checkout, local
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

`FOSSIL_VFS`: Name a VFS to load into SQLite.

`GATEWAY_INTERFACE`: If present and the `--nocgi` option is not, assume
fossil is invoked from a web server as a CGI command, and act
accordingly.

`HOME`: Location of the `~/.fossil` file. The first environment
variable found in the environment from the list `FOSSIL_HOME`,
`LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and
`HOMEPATH` (Windows, used together), and `HOME` is used as the
location of the `~/.fossil` file.

`HOMEDRIVE`, `HOMEPATH`: (Windows) Location of the `~/.fossil` file.
The first environment variable found in the environment from the list
`FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows),
`HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is
used as the location of the `~/.fossil` file.








|
<
<
<
|







179
180
181
182
183
184
185
186



187
188
189
190
191
192
193
194

`FOSSIL_VFS`: Name a VFS to load into SQLite.

`GATEWAY_INTERFACE`: If present and the `--nocgi` option is not, assume
fossil is invoked from a web server as a CGI command, and act
accordingly.

`HOME`: Potential location of the [configuration database][configdb].



See the [configuration database location][configloc] description for details.

`HOMEDRIVE`, `HOMEPATH`: (Windows) Location of the `~/.fossil` file.
The first environment variable found in the environment from the list
`FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows),
`HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is
used as the location of the `~/.fossil` file.

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
in the clone even before any users have been created, and in that case
it will be the new admin user. If `default-user` is not set, then the
first found environment variable from the list `FOSSIL_USER`, `USER`,
`LOGNAME`, and `USERNAME`, is the user name. As a final fallback, if
none of those are set, then the default user name is "root".


### Home Directory

Fossil keeps some information interesting to each user in the user's

home directory. This includes the global settings and the list of
repositories and checkouts used by `fossil all`.

The user's home directory is specified by the first environment
variable found in the environment from the list `FOSSIL_HOME`,
`LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and
`HOMEPATH` (Windows, used together), and `HOME`.


SQLite has its own notion of the user's home directory, which is only
exposed if the interactive SQL shell is run with the "fossil
sqlite3" command. Being a separate library, SQLite uses many of the
same variables to find the home directory, but uses them in a
different order, and does not use the `FOSSIL_HOME` variable at all.






### SQLite VFS to use

See [the SQLite documentation](http://www.sqlite.org/vfs.html) for an
explanation of what a VFS actually is and what it does.

If the default VFS underneath SQLite is not suitable, an alternative







|

|
>
|
|

<
|
|
|
>

<
|
|
|
<

>

>
>







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
in the clone even before any users have been created, and in that case
it will be the new admin user. If `default-user` is not set, then the
first found environment variable from the list `FOSSIL_USER`, `USER`,
`LOGNAME`, and `USERNAME`, is the user name. As a final fallback, if
none of those are set, then the default user name is "root".


### Configuration Database Location

Fossil keeps some information pertinent to each user in the user's
[configuration database file][configdb]. 
The configuration database file includes the global settings
and the list of repositories and checkouts used by `fossil all`.


The location of the configuration database file depends on the
operating system and on the existance of various environment
variables and/or files.  In brief, the configuration database is
usually:


  *  Traditional unix &rarr; "`$HOME/.fossil`"
  *  Windows &rarr; "`%LOCALAPPDATA%/_fossil`"
  *  [XDG-unix][xdg] &rarr; "`$HOME/.config/fossil.db`"


[xdg]: https://www.freedesktop.org/wiki/

See the [configuration database location
algorithm][configloc] discussion for full information.

### SQLite VFS to use

See [the SQLite documentation](http://www.sqlite.org/vfs.html) for an
explanation of what a VFS actually is and what it does.

If the default VFS underneath SQLite is not suitable, an alternative
489
490
491
492
493
494
495



`google-chrome` that it can find on the `PATH`.

On Apple platforms, it assumes that `open` is the command to open an
URL in the user's configured default browser.

On Windows platforms, it assumes that `start` is the command to open
an URL in the user's configured default browser.










>
>
>
474
475
476
477
478
479
480
481
482
483
`google-chrome` that it can find on the `PATH`.

On Apple platforms, it assumes that `open` is the command to open an
URL in the user's configured default browser.

On Windows platforms, it assumes that `start` is the command to open
an URL in the user's configured default browser.

[configdb]: ./tech_overview.wiki#configdb
[configloc]: ./tech_overview.wiki#configloc
Changes to www/faq.wiki.
1
2
3
4


5
6
7
8
9
10
11
<title>Fossil FAQ</title>
<h1 align="center">Frequently Asked Questions</h1>

<p>Note: See also <a href="qandc.wiki">Questions and Criticisms</a>.



<ol>
<li><a href="#q1">What GUIs are available for fossil?</a></li>
<li><a href="#q2">What is the difference between a "branch" and a "fork"?</a></li>
<li><a href="#q3">How do I create a new branch?</a></li>
<li><a href="#q4">How do I tag a check-in?</a></li>
<li><a href="#q5">How do I create a private branch that won't get pushed back to the



|
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
<title>Fossil FAQ</title>
<h1 align="center">Frequently Asked Questions</h1>

<p>Note:
This page is old and has not been kept up-to-date.  See the
[/finfo?name=www/faq.wiki|change history of this page].</p>

<ol>
<li><a href="#q1">What GUIs are available for fossil?</a></li>
<li><a href="#q2">What is the difference between a "branch" and a "fork"?</a></li>
<li><a href="#q3">How do I create a new branch?</a></li>
<li><a href="#q4">How do I tag a check-in?</a></li>
<li><a href="#q5">How do I create a private branch that won't get pushed back to the
Changes to www/fileformat.wiki.
341
342
343
344
345
346
347

348
349
350
351
352
353
354

A wiki artifact defines a single version of a
single wiki page.
Wiki artifacts accept
the following card types:

<blockquote>

<b>D</b> <i>time-and-date-stamp</i><br />
<b>L</b> <i>wiki-title</i><br />
<b>N</b> <i>mimetype</i><br />
<b>P</b> <i>parent-artifact-id</i>+<br />
<b>U</b> <i>user-name</i><br />
<b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
<b>Z</b> <i>checksum</i>







>







341
342
343
344
345
346
347
348
349
350
351
352
353
354
355

A wiki artifact defines a single version of a
single wiki page.
Wiki artifacts accept
the following card types:

<blockquote>
<b>C</b> <i>change-comment</i><br>
<b>D</b> <i>time-and-date-stamp</i><br />
<b>L</b> <i>wiki-title</i><br />
<b>N</b> <i>mimetype</i><br />
<b>P</b> <i>parent-artifact-id</i>+<br />
<b>U</b> <i>user-name</i><br />
<b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
<b>Z</b> <i>checksum</i>
364
365
366
367
368
369
370







371
372
373
374
375
376
377
the usual checksum over the entire artifact and is required.

The <b>W</b> card is used to specify the text of the wiki page.  The
argument to the <b>W</b> card is an integer which is the number of bytes
of text in the wiki page.  That text follows the newline character
that terminates the <b>W</b> card.  The wiki text is always followed by one
extra newline.








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

<a name="tktchng"></a>
<h3>2.5 Ticket Changes</h3>








>
>
>
>
>
>
>







365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
the usual checksum over the entire artifact and is required.

The <b>W</b> card is used to specify the text of the wiki page.  The
argument to the <b>W</b> card is an integer which is the number of bytes
of text in the wiki page.  That text follows the newline character
that terminates the <b>W</b> card.  The wiki text is always followed by one
extra newline.

The <b>C</b> card on a wiki page is optional.  The argument is a comment
that explains why the changes was made.  The ability to have a <b>C</b>
card on a wiki page artifact was added on 2019-12-02 at the suggestion
of user George Krivov and is not currently used or generated by the 
implementation. Older versions of Fossil will reject a wiki-page
artifact that includes a <b>C</b> card.

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

<a name="tktchng"></a>
<h3>2.5 Ticket Changes</h3>

651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
<td>&nbsp;</td>
</tr>
<tr>
<td><b>C</b> <i>comment-text</i></td>
<td align=center><b>1</b></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td align=center><b>0-1</b></td>
<td align=center><b>0-1</b></td>
<td>&nbsp;</td>
</tr>
<tr>
<td><b>D</b> <i>date-time-stamp</i></td>







|







659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
<td>&nbsp;</td>
</tr>
<tr>
<td><b>C</b> <i>comment-text</i></td>
<td align=center><b>1</b></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td align=center><b>0-1</b></td>
<td>&nbsp;</td>
<td align=center><b>0-1</b></td>
<td align=center><b>0-1</b></td>
<td>&nbsp;</td>
</tr>
<tr>
<td><b>D</b> <i>date-time-stamp</i></td>
Changes to www/fossil-v-git.wiki.
30
31
32
33
34
35
36
37

38
39
40



41
42



43
44



45





46



47
48



49
50



51
52



53
54



55
56



57
58



59
60


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

<h2>2.0 Differences Between Fossil And Git</h2>

Differences between Fossil and Git are summarized by the following table,
with further description in the text that follows.

<blockquote><table border=1 cellpadding=5 align=center>
<tr><th width="50%">GIT</th><th width="50%">FOSSIL</th></tr>

<tr><td>File versioning only</td>
    <td>VCS, tickets, wiki, docs, notes, forum, UI,
    [https://en.wikipedia.org/wiki/Role-based_access_control|RBAC]</td></tr>



<tr><td>Sprawling, incoherent, and inefficient</td>
    <td>Self-contained and efficient</td></tr>



<tr><td>Ad-hoc pile-of-files key/value database</td>
    <td>[https://sqlite.org/famous.html|The most popular database in the world]</td></tr>



<tr><td>Portable to POSIX systems only</td><td>Runs just about anywhere</td></tr>





<tr><td>Bazaar-style development</td><td>Cathedral-style development</td></tr>



<tr><td>Designed for Linux kernel development</td>
    <td>Designed for SQLite development</td></tr>



<tr><td>Many contributors</td>
    <td>Select contributors</td></tr>



<tr><td>Focus on individual branches</td>
    <td>Focus on the entire tree of changes</td></tr>



<tr><td>One check-out per repository</td>
    <td>Many check-outs per repository</td></tr>



<tr><td>Remembers what you should have done</td>
    <td>Remembers what you actually did</td></tr>



<tr><td>Commit first</td>
    <td>Test first</td></tr>



<tr><td>SHA-2</td>
    <td>SHA-3</td></tr>


</table></blockquote>

<h3 id="features">2.1 Featureful</h3>

Git provides file versioning services only, whereas Fossil adds
an integrated [./wikitheory.wiki | wiki],
[./bugtheory.wiki | ticketing &amp; bug tracking],
[./embeddeddoc.wiki | embedded documentation], 
[./event.wiki | technical notes], and a [./forum.wiki | web forum],
all within a single nicely-designed [./customskin.md|skinnable] web
[/help?cmd=ui|UI],
protected by [./caps/ | a fine-grained role-based
access control system].
These additional capabilities are available for Git as 3rd-party
add-ons, but with Fossil they are integrated into
the design.  One way to describe Fossil is that it is
"[https://github.com/ | GitHub]-in-a-box."

Fossil can do operations over all local repo clones and check-out
directories with a single command. For example, Fossil lets you say
<tt>fossil all pull</tt> on a laptop prior to taking it off the network
hosting those repos. You can sync up to all of the private repos on your
company network plus those public Internet-hosted repos you use. Whether
going out for a working lunch or on a transoceanic an airplane trip, one
command gets you in sync. This works with several other Fossil
sub-commands, such as <tt>fossil all changes</tt> to get a list of files
that you forgot to commit prior to the end of your working day, across
all repos.

Whenever Fossil is told to modify the local checkout in some destructive
way ([/help?cmd=rm|fossil rm], [/help?cmd=update|fossil update],







|
>
|

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




















|


|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

<h2>2.0 Differences Between Fossil And Git</h2>

Differences between Fossil and Git are summarized by the following table,
with further description in the text that follows.

<blockquote><table border=1 cellpadding=5 align=center>
<tr><th width="49%">GIT</th><th width="49%">FOSSIL</th><th width="2%">more</th></tr>
<tr>
    <td>File versioning only</td>
    <td>VCS, tickets, wiki, docs, notes, forum, UI,
    [https://en.wikipedia.org/wiki/Role-based_access_control|RBAC]</td>
    <td><a href="#features">2.1&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Sprawling, incoherent, and inefficient</td>
    <td>Self-contained and efficient</td>
    <td><a href="#efficient">2.2&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Ad-hoc pile-of-files key/value database</td>
    <td>[https://sqlite.org/famous.html|The most popular database in the world]</td>
    <td><a href="#durable">2.3&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Portable to POSIX systems only</td>
    <td>Runs just about anywhere</td>
    <td><a href="#portable">2.4&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Bazaar-style development</td>
    <td>Cathedral-style development</td>
    <td><a href="#devorg">2.5.1&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Designed for Linux kernel development</td>
    <td>Designed for SQLite development</td>
    <td><a href="#scale">2.5.2&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Many contributors</td>
    <td>Select contributors</td>
    <td><a href="#contrib">2.5.3&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Focus on individual branches</td>
    <td>Focus on the entire tree of changes</td>
    <td><a href="#branches">2.5.4&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>One check-out per repository</td>
    <td>Many check-outs per repository</td>
    <td><a href="#checkouts">2.6&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Remembers what you should have done</td>
    <td>Remembers what you actually did</td>
    <td><a href="#history">2.7&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Commit first</td>
    <td>Test first</td>
    <td><a href="#testing">2.8&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>SHA-2</td>
    <td>SHA-3</td>
    <td><a href="#hash">2.9&nbsp;&darr;</a></td>
</tr>
</table></blockquote>

<h3 id="features">2.1 Featureful</h3>

Git provides file versioning services only, whereas Fossil adds
an integrated [./wikitheory.wiki | wiki],
[./bugtheory.wiki | ticketing &amp; bug tracking],
[./embeddeddoc.wiki | embedded documentation], 
[./event.wiki | technical notes], and a [./forum.wiki | web forum],
all within a single nicely-designed [./customskin.md|skinnable] web
[/help?cmd=ui|UI],
protected by [./caps/ | a fine-grained role-based
access control system].
These additional capabilities are available for Git as 3rd-party
add-ons, but with Fossil they are integrated into
the design.  One way to describe Fossil is that it is
"[https://github.com/ | GitHub]-in-a-box."

Fossil can do operations over all local repo clones and check-out
directories with a single command. For example, Fossil lets you say
<tt>fossil all sync</tt> on a laptop prior to taking it off the network
hosting those repos. You can sync up to all of the private repos on your
company network plus those public Internet-hosted repos you use. Whether
going out for a working lunch or on a transoceanic airplane trip, one
command gets you in sync. This works with several other Fossil
sub-commands, such as <tt>fossil all changes</tt> to get a list of files
that you forgot to commit prior to the end of your working day, across
all repos.

Whenever Fossil is told to modify the local checkout in some destructive
way ([/help?cmd=rm|fossil rm], [/help?cmd=update|fossil update],
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
part of the job, which can be recombined (by experts) to perform
powerful operations. Git has a lot of complexity and many dependencies,
so that most people end up installing it via some kind of package
manager, simply because the creation of complicated binary packages is
best delegated to people skilled in their creation. Normal Git users are
not expected to build Git from source and install it themselves.

Fossil is a single self-contained stand-alone executable with hardly any











dependencies. Fossil can be run inside a minimally configured
[https://en.wikipedia.org/wiki/Chroot|chroot jail], from a Windows
memory stick, off a Raspberry Pi with a tiny SD card, etc. To install
Fossil, one merely puts the executable somewhere in the <tt>$PATH</tt>.
Fossil is
[https://fossil-scm.org/fossil/doc/trunk/www/build.wiki|straightforward
to build and install], so that many Fossil users do in fact build and
install "trunk" versions to get new features between formal releases.











Some say that Git more closely adheres to the Unix philosophy,
summarized as "many small tools, loosely joined," but we have many
examples of other successful Unix software that violates that principle
to good effect, from Apache to Python to ZFS. We can infer from that
that this is not an absolute principle of good software design.
Sometimes "many features, tightly-coupled" works better. What actually
matters is effectiveness and efficiency. We believe Fossil achieves
this.




Git fails on efficiency once you add to it all of the third-party
software needed to give it a Fossil-equivalent feature set. Consider
[https://about.gitlab.com/|GitLab], a third-party extension to Git
wrapping it in many features, making it roughly Fossil-equivalent,
though [https://docs.gitlab.com/ee/install/requirements.html|much more
resource hungry] and hence more costly to run than the equivalent
Fossil setup. GitLab's basic requirements are easy to accept when you're dedicating
a local rack server or blade to it, since its minimum requirements are
more or less a description of the smallest
thing you could call a "server" these days, but when you go to host that
in the cloud, you can expect to pay about 8 as much to comfortably host
GitLab as for Fossil.³ This difference is largely due to basic
technology choices: Ruby and PostgreSQL vs C and SQLite.

The Fossil project itself is [./selfhost.wiki|hosted on a very small
VPS], and we've received many reports on the Fossil forum about people
successfully hosting Fossil service on bare-bones $5/month VPS hosts,
spare Raspberry Pi boards, and other small hosts.







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



>
>
>
>
>
>
>
>
>
>










>
>
>
|
|








|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
part of the job, which can be recombined (by experts) to perform
powerful operations. Git has a lot of complexity and many dependencies,
so that most people end up installing it via some kind of package
manager, simply because the creation of complicated binary packages is
best delegated to people skilled in their creation. Normal Git users are
not expected to build Git from source and install it themselves.

Fossil is a single self-contained stand-alone executable which by default
depends only on common platform libraries. If your platform allows static
linking &mdash; not all do these days! &mdash; you can even get it down to
a single executable with no external dependencies at all. Most notably,
we deliver the official Windows builds of Fossil this way: the Zip file
contains only <tt>fossil.exe</tt>, a self-contained Fossil executable;
it is not a <tt>setup.exe</tt> style installer, it is the whole enchilada.

A typical Fossil executable is about 5&nbsp;MiB, not counting system
libraries it shares in common with Git such as OpenSSL and zlib, which
we can factor out of the discussion.

These properties allow Fossil to easily run inside a minimally configured
[https://en.wikipedia.org/wiki/Chroot|chroot jail], from a Windows memory
stick, off a Raspberry Pi with a tiny SD card, etc. To install Fossil,
one merely puts the executable somewhere in the <tt>$PATH</tt>. Fossil is

[https://fossil-scm.org/fossil/doc/trunk/www/build.wiki|straightforward
to build and install], so that many Fossil users do in fact build and
install "trunk" versions to get new features between formal releases.

Contrast a basic installation of Git, which takes up about
15&nbsp;MiB on Debian 10 across 230 files, not counting the contents of
<tt>/usr/share/doc</tt> or <tt>/usr/share/locale</tt>. If you need to
deploy to any platform where you cannot count facilities like the POSIX
shell, Perl interpreter, and Tcl/Tk platform needed to fully use Git
as part of the base platform, the full footprint of a Git installation
extends to more like 45&nbsp;MiB and thousands of files. This complicates
several common scenarios: Git for Windows, chrooted Git servers,
Docker images...

Some say that Git more closely adheres to the Unix philosophy,
summarized as "many small tools, loosely joined," but we have many
examples of other successful Unix software that violates that principle
to good effect, from Apache to Python to ZFS. We can infer from that
that this is not an absolute principle of good software design.
Sometimes "many features, tightly-coupled" works better. What actually
matters is effectiveness and efficiency. We believe Fossil achieves
this.

The above size comparisons aren't apples-to-apples anyway. We've
compared the size of Fossil with all of its [#features | many built-in
features] to a fairly minimal Git installation. You must add a lot
of third-party
software to Git to give it a Fossil-equivalent feature set. Consider
[https://about.gitlab.com/|GitLab], a third-party extension to Git
wrapping it in many features, making it roughly Fossil-equivalent,
though [https://docs.gitlab.com/ee/install/requirements.html|much more
resource hungry] and hence more costly to run than the equivalent
Fossil setup. GitLab's basic requirements are easy to accept when you're dedicating
a local rack server or blade to it, since its minimum requirements are
more or less a description of the smallest
thing you could call a "server" these days, but when you go to host that
in the cloud, you can expect to pay about 8× as much to comfortably host
GitLab as for Fossil.³ This difference is largely due to basic
technology choices: Ruby and PostgreSQL vs C and SQLite.

The Fossil project itself is [./selfhost.wiki|hosted on a very small
VPS], and we've received many reports on the Fossil forum about people
successfully hosting Fossil service on bare-bones $5/month VPS hosts,
spare Raspberry Pi boards, and other small hosts.
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213


214
215
216
217
218
219
220
[http://catb.org/jargon/html/G/grovel.html|groveling] the
[https://www.git-scm.com/docs/git-log|commit log].  With Git, if you
are looking at some historical check-in then you cannot ask "What came
next?" or "What are the children of this check-in?"

Fossil, on the other hand, parses essential information about check-ins
(parents, children, committers, comments, files changed, etc.) into a
relational database that can be easily queried using concise SQL
statements to find both ancestors and descendants of a check-in. This is
the hybrid data model mentioned above: Fossil manages your check-in and
other data in a NoSQL block chain structured data store, but that's backed
by a set of relational lookup tables for quick indexing into that
artifact store.  (See "[./theory1.wiki|Thoughts On The Design Of The
Fossil DVCS]" for more details.)

Leaf check-ins in Git that lack a "ref" become "detached," making them
difficult to locate and subject to garbage collection. This
[http://gitfaq.org/articles/what-is-a-detached-head.html|detached head
state] problem has caused untold grief for countless Git users. With


Fossil, detached heads are simply impossible because we can always find
our way back into the block chain using one or more of the relational
indices it automatically manages for you.

This design difference shows up in several other places within each
tool. It is why Fossil's [/help?cmd=timeline|timeline] is generally more
detailed yet more clear than those available in Git front-ends.







|










|
>
>







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
[http://catb.org/jargon/html/G/grovel.html|groveling] the
[https://www.git-scm.com/docs/git-log|commit log].  With Git, if you
are looking at some historical check-in then you cannot ask "What came
next?" or "What are the children of this check-in?"

Fossil, on the other hand, parses essential information about check-ins
(parents, children, committers, comments, files changed, etc.) into a
relational database that can easily be queried using concise SQL
statements to find both ancestors and descendants of a check-in. This is
the hybrid data model mentioned above: Fossil manages your check-in and
other data in a NoSQL block chain structured data store, but that's backed
by a set of relational lookup tables for quick indexing into that
artifact store.  (See "[./theory1.wiki|Thoughts On The Design Of The
Fossil DVCS]" for more details.)

Leaf check-ins in Git that lack a "ref" become "detached," making them
difficult to locate and subject to garbage collection. This
[http://gitfaq.org/articles/what-is-a-detached-head.html|detached head
state] problem has caused untold grief for
[https://www.google.com/search?q=git+detached+head+state | a huge number
of Git users]. With
Fossil, detached heads are simply impossible because we can always find
our way back into the block chain using one or more of the relational
indices it automatically manages for you.

This design difference shows up in several other places within each
tool. It is why Fossil's [/help?cmd=timeline|timeline] is generally more
detailed yet more clear than those available in Git front-ends.
560
561
562
563
564
565
566

567
568
569
570
571
572
573
574
575
576
577








578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608



609
610
611
612
613
614
615
616
617
618

619
620
621
622
623
624
625
changes on all branches all at once helps keep the whole team
up-to-date with what everybody else is doing, resulting in a more 
tightly focused and cohesive implementation.


<h3 id="checkouts">2.6 One vs. Many Check-outs per Repository</h3>


The default mode of operation in Git is to have a single working
directory with a single <tt>.git</tt> subdirectory holding the actual
local repository contents.

Fossil doesn't work that way. A Fossil repository is a SQLite database
file which is normally stored outside the working directory. You can
[/help?cmd=open | open] a Fossil repository any number of times into
any number of working directories. A common usage pattern is to have one
working directory per active working branch, so that switching branches
is done with a <tt>cd</tt> command rather than by checking out the
branches successively in a single working directory.









You can use Git in the Fossil style, either by manually symlinking the
<tt>.git</tt> directory from one working directory to another or by use
of the <tt>[https://git-scm.com/docs/git-worktree|git-worktree]</tt>
feature. Nevertheless, Git's default tie between working directory and
repository means the standard method for working with a Git repo is to
have one working directory only. Most Git tutorials teach this style, so
it is how most people learn to use Git. Because relatively few people
use Git with multiple working directories per repository, there are
[https://duckduckgo.com/?q=git+worktree+problem | several known
problems] in working that way, which don't happen in Fossil because of
the clear separation between repository and working directory.

Switching branches inside a single working directory loses local context
on each switch.

For instance, in any software project where the runnable program must be
built from source files, you invalidate build objects on each switch,
artificially increasing the time required to switch versions. This
affects software written in statically-compiled programming languages
such as C, Java, and Haskell, but it can even affect programs written in
dynamic languages like JavaScript. A common
[https://en.wikipedia.org/wiki/Single-page_application | SPA] build
process involves a [http://browserify.org/ | Browserify] pass to convert
[https://nodejs.org/ | Node] packages to run in a web browser,
[https://sass-lang.com | SASS files] to CSS,
[https://www.typescriptlang.org | Typescript] to JavaScript, etc., to
say nothing of [https://github.com/mishoo/UglifyJS | uglification] and
other passes. Once all that processing work is done for a given input
file in a given working directory, why re-do that work just to switch
versions?




For another example, you might have an active long-running test grinding
away in a working directory, then get a call from a customer requiring
that you switch to a stable branch to answer questions in terms of the
version that customer is running. You don't want to stop the test in
order to switch your lone working directory to the stable branch.

Disk space is cheap. Having several working directories, each with its
own local state, makes switching versions cheap and fast. Plus,
<tt>cd</tt> is faster to type than <tt>git checkout</tt>.



<h3 id="history">2.7 What you should have done vs. What you actually did</h3>

Git puts a lot of emphasis on maintaining
a "clean" check-in history.  Extraneous and experimental branches by
individual developers often never make it into the main repository.  And







>
|
|
<


|





>
>
>
>
>
>
>
>










|


|




|


|

|
|
|
|
|
|

|
>
>
>









|
>







623
624
625
626
627
628
629
630
631
632

633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
changes on all branches all at once helps keep the whole team
up-to-date with what everybody else is doing, resulting in a more 
tightly focused and cohesive implementation.


<h3 id="checkouts">2.6 One vs. Many Check-outs per Repository</h3>

Because Git commingles the repository data with the initial checkout of
that repository, the default mode of operation in Git is to stick to that
single work/repo tree, even when that's a shortsighted way of working.


Fossil doesn't work that way. A Fossil repository is a SQLite database
file which is normally stored outside the working checkout directory. You can
[/help?cmd=open | open] a Fossil repository any number of times into
any number of working directories. A common usage pattern is to have one
working directory per active working branch, so that switching branches
is done with a <tt>cd</tt> command rather than by checking out the
branches successively in a single working directory.

Fossil does allow you to switch branches within a working checkout
directory, and this is also often done. It is simply that there is no
inherent penalty to either choice in Fossil as there is in Git. The
standard advice is to use a switch-in-place workflow in Fossil when
the disturbance from switching branches is small, and to use multiple
checkouts when you have long-lived working branches that are different
enough that switching in place is disruptive.

You can use Git in the Fossil style, either by manually symlinking the
<tt>.git</tt> directory from one working directory to another or by use
of the <tt>[https://git-scm.com/docs/git-worktree|git-worktree]</tt>
feature. Nevertheless, Git's default tie between working directory and
repository means the standard method for working with a Git repo is to
have one working directory only. Most Git tutorials teach this style, so
it is how most people learn to use Git. Because relatively few people
use Git with multiple working directories per repository, there are
[https://duckduckgo.com/?q=git+worktree+problem | several known
problems] with that way of working, problems which don't happen in Fossil because of
the clear separation between repository and working directory.

This distinction matters because switching branches inside a single working directory loses local context
on each switch.

For instance, in any software project where the runnable program must be
built from source files, you invalidate build objects on each switch,
artificially increasing the time required to switch versions. Most obviously, this
affects software written in statically-compiled programming languages
such as C, Java, and Haskell, but it can even affect programs written in
dynamic languages like JavaScript. A typical
[https://en.wikipedia.org/wiki/Single-page_application | SPA] build
process involves several passes: [http://browserify.org/ | Browserify] to convert
[https://nodejs.org/ | Node] packages so they'll run in a web browser,
[https://sass-lang.com | SASS] to CSS translation,
transpilation of [https://www.typescriptlang.org | Typescript] to JavaScript,
[https://github.com/mishoo/UglifyJS | uglification], etc.
Once all that processing work is done for a given input
file in a given working directory, why re-do that work just to switch
versions? If most of the files that differ between versions don't change
very often, you can save substantial time by switching branches with
<tt>cd</tt> rather than swapping versions in-place within a working
checkout directory.

For another example, you might have an active long-running test grinding
away in a working directory, then get a call from a customer requiring
that you switch to a stable branch to answer questions in terms of the
version that customer is running. You don't want to stop the test in
order to switch your lone working directory to the stable branch.

Disk space is cheap. Having several working directories, each with its
own local state, makes switching versions cheap and fast. Plus,
<tt>cd</tt> is faster to type than <tt>git checkout</tt> or <tt>fossil
update</tt>.


<h3 id="history">2.7 What you should have done vs. What you actually did</h3>

Git puts a lot of emphasis on maintaining
a "clean" check-in history.  Extraneous and experimental branches by
individual developers often never make it into the main repository.  And
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
an opportunity to test the change first locally unless you give the
<tt>--no-commit</tt> option.

Fossil cannot sensibly work that way because of its default-enabled
autosync feature. Instead of jumping straight to the commit step, Fossil
applies the proposed merge to the local working directory only,
requiring a separate check-in step before the change is committed to the
repository blockchain. This gives you a chance to test the change,
whether manually, or by running your software's automatic tests, or
both.

Another difference is that because Fossil requires an explicit commit
for a merge, it makes you give an explicit commit <i>message</i> for
each merge, whereas Git writes that commit message itself by default
unless you give the optional <tt>--edit</tt> flag to override it.

We don't look at this difference as a workaround in Fossil for autosync,







|
|
|







757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
an opportunity to test the change first locally unless you give the
<tt>--no-commit</tt> option.

Fossil cannot sensibly work that way because of its default-enabled
autosync feature. Instead of jumping straight to the commit step, Fossil
applies the proposed merge to the local working directory only,
requiring a separate check-in step before the change is committed to the
repository blockchain. This gives you a chance to test the change first,
either manually or by running your software's automatic tests. (Ideally,
both!)

Another difference is that because Fossil requires an explicit commit
for a merge, it makes you give an explicit commit <i>message</i> for
each merge, whereas Git writes that commit message itself by default
unless you give the optional <tt>--edit</tt> flag to override it.

We don't look at this difference as a workaround in Fossil for autosync,
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765









766


767
768




769
770
771
772
773
774
775
776
777
778
779
780
781

Fossil's implementation of the feature is also simpler to describe. The
brief online help for <tt>[/help?cmd=merge | fossil merge]</tt> is
currently 41 lines long, to which you want to add the 600 lines of
[./branching.wiki | the branching document]. The equivalent
documentation in Git is the aggregation of the man pages for the above
three commands, which is over 1000 lines, much of it mutually redundant.
(e.g.  the <tt>--edit</tt> and <tt>--no-commit</tt> options get
described three times, each time differently.) Fossil's
documentation is not only more concise, it gives a nice split of brief
online help and full online documentation.


<h3 id="hash">2.9 Hash Algorithm: SHA-3 vs SHA-2 vs SHA-1</h3>

Fossil started out using 160-bit SHA-1 hashes to identify check-ins,
just as in Git. That changed in early 2017 when news of the
[https://shattered.io/|SHAttered attack] broke, demonstrating that SHA-1
collisions were now practical to create. Two weeks later, the creator of
Fossil delivered a new release allowing a clean migration to
[https://en.wikipedia.org/wiki/SHA-3|256-bit SHA-3] with
[./hashpolicy.wiki|full backwards compatibility] to old SHA-1 based
repositories.

By mid-2019, that feature arrived in every software package repository
shipping Fossil, the last mover being Debian's stable package repo,
which has a highly conservative policy on upgrading to new versions.
With that hurdle run, we were able to change the default hash mode in
Fossil 2.10 (released 2019-10-04) to require SHA-3 support both for new
repositories and to create SHA-3 hashes in existing repos, effectively
upgrading them if they were created with Fossil 1.<i>x</i>. This not
only solves the SHAttered problem, it should prevent a reoccurrence of
similar problems for the foreseeable future.

Meanwhile, the Git community took until August 2018 to announce
[https://git-scm.com/docs/hash-function-transition/2.18.0|their plan]
for solving the same problem by moving to SHA-256 (a variant of the
[https://en.wikipedia.org/wiki/SHA-2|older SHA-2 algorithm]) and until









February 2019 to release a version containing the change. It's looking


like this will take years more to percolate through the community.





The practical impact of SHAttered on structured data stores like the one
in Git and Fossil isn't clear, but you want to have your repositories
moved over to a stronger hash algorithm before someone figures out how
to make use of the weaknesses in the old one.  Fossil's developers moved
on this problem quickly and had a widely-deployed solution to it years
ago.

<hr/>

<h3>Asides and Digressions</h3>

<i><small><ol>
    <li><p>[./mirrorlimitations.md|Many







|
















|
|
<
|
|
<
|



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

>
>
>
>
|
|

|
|
<







803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828

829
830

831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861

862
863
864
865
866
867
868

Fossil's implementation of the feature is also simpler to describe. The
brief online help for <tt>[/help?cmd=merge | fossil merge]</tt> is
currently 41 lines long, to which you want to add the 600 lines of
[./branching.wiki | the branching document]. The equivalent
documentation in Git is the aggregation of the man pages for the above
three commands, which is over 1000 lines, much of it mutually redundant.
(e.g.  Git's <tt>--edit</tt> and <tt>--no-commit</tt> options get
described three times, each time differently.) Fossil's
documentation is not only more concise, it gives a nice split of brief
online help and full online documentation.


<h3 id="hash">2.9 Hash Algorithm: SHA-3 vs SHA-2 vs SHA-1</h3>

Fossil started out using 160-bit SHA-1 hashes to identify check-ins,
just as in Git. That changed in early 2017 when news of the
[https://shattered.io/|SHAttered attack] broke, demonstrating that SHA-1
collisions were now practical to create. Two weeks later, the creator of
Fossil delivered a new release allowing a clean migration to
[https://en.wikipedia.org/wiki/SHA-3|256-bit SHA-3] with
[./hashpolicy.wiki|full backwards compatibility] to old SHA-1 based
repositories.

In October 2019, after the last of the major binary
package repos offering Fossil upgraded to Fossil 2.<i>x</i>,

we switched the default hash mode so that from
Fossil 2.10 forward, the conversion to SHA-3 is fully automatic.

This not
only solves the SHAttered problem, it should prevent a reoccurrence of
similar problems for the foreseeable future.

Meanwhile, the Git community took until August 2018 to publish
[https://git-scm.com/docs/hash-function-transition/|their first plan]
for solving the same problem by moving to SHA-256, a variant of the
[https://en.wikipedia.org/wiki/SHA-2 | older SHA-2 algorithm].  As of
this writing in February 2020, that plan hasn't been implemented, as far
as this author is aware, but there is now
[https://lwn.net/ml/git/20200113124729.3684846-1-sandals@crustytoothpaste.net/
| a competing SHA-256 based plan] which requires complete repository
conversion from SHA-1 to SHA-256, breaking all public hashes in the
repo. One way to characterize such a massive upheaval in Git terms is a
whole-project rebase, which violates
[https://blog.axosoft.com/golden-rule-of-rebasing-in-git/ | Git's own
Golden Rule of Rebasing].

Regardless of the eventual implementation details, we fully expect Git
to move off SHA-1 eventually and for the changes to take years more to
percolate through the community.

Almost three years after Fossil solved this problem, the
[https://sha-mbles.github.io/ | SHAmbles attack] was published, further
weakening the case for continuing to use SHA-1.

The practical impact of attacks like SHAttered and SHAmbles on the
Git and Fossil blockchains isn't clear, but you want to have your repositories
moved over to a stronger hash algorithm before someone figures out how
to make use of the weaknesses in the old one. Fossil has had this covered
for years now, so that the solution is now almost universally deployed.


<hr/>

<h3>Asides and Digressions</h3>

<i><small><ol>
    <li><p>[./mirrorlimitations.md|Many
Added www/gitusers.md.


























































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# Hints For Users With Prior Git Experience

This document is a semi-random collection of hints intended to help
new users of Fossil who have had prior exposure to Git.  In other words,
this document tries to describe the differences in how Fossil works 
from the perspective of Git users.

## Help Improve This Document

If you have a lot of prior Git experience, and you are new to Fossil
and are struggling with some concepts, please ask for help on the
[Fossil Forum][1].  The people who write this document are intimately
familiar with Fossil and less familiar with Git.  It is difficult for
us to anticipate the perspective of people who are initimately familiar
with Git and less familiar with Fossil.  Asking questions on the Forum
will help us to improve the document.

[1]:  https://fossil-scm.org/forum

Specific suggestions on how to improve this document are also welcomed,
of course.

## Repositories And Checkouts Are Distinct

A repository and a check-out are distinct concepts in Fossil, whereas
the two are often conflated with Git.  A repository is a database in
which the entire history of a project is stored.  A check-out is a
directory hierarchy that contains a snapshot of your project that you
are currently working on.  See [detailed definitions][2] for more
information.  With Git, the repository and check-out are closely
related - the repository is the contents of the "`.git`" subdirectory
at the root of your check-out.  But with Fossil, the repository and
the check-out are completely separate.  A Fossil repository can reside
in the same directory hierarchy with the check-out as with Git, but it
is more common to put the repository in a separate directory.

[2]: ./whyusefossil.wiki#definitions

Fossil repositories are a single file, rather than being a directory
hierarchy as with the "`.git`" folder in Git.  The repository file
can be named anything you want, but it is best to use the "`.fossil`"
suffix.  Many people choose to gather all of their Fossil repositories
in a single directory on their machine, such as "`~/Fossils`" or
"`C:\Fossils`".  This can help humans to keep their repositories
organized, but Fossil itself doesn't really care.

Because Fossil cleanly separates the repository from the check-out, it
is routine to have multiple check-outs from the same repository.  Each
check-out can be on a separate branch, or on the same branch.  Each
check-out operates independently of the others.

Each Fossil check-out contains a file (usually named "`.fslckout`" on
unix or "`_FOSSIL_`" on Windows) that keeps track of the status of that
particular check-out and keeps a pointer to the repository.  If you
move or rename the repository file, the check-outs won't be able to find 
it and will complain.  But you can freely move check-outs around without
causing any problems.

## There Is No Staging Area

Fossil omits the "Git index" or "staging area" concept.  When you
type "`fossil commit`" _all_ changes in your check-out are committed,
automatically.  There is no need for the "-a" option as with Git.

If you only want to commit just some of the changes, you can list the names
of the files you want to commit as arguments, like this:

        fossil commit src/main.c doc/readme.md

## Create Branches After-The-Fact

Fossil perfers that you create new branches when you commit using
the "`--branch` _BRANCH-NAME_" command-line option.  For example:

        fossil commit --branch my-new-branch

It is not necessary to create branches ahead of time, as in Git, though
that is allowed using the "`fossil branch new`" command, if you
prefer.  Fossil also allows you to move a check-in to a different branch
*after* you commit it, using the "`fossil amend`" command.
For example:

        fossil amend current --branch my-new-branch

## Autosync

Fossil has a feature called "[autosync][5]".  Autosync defaults on.
When autosync is enabled, Fossil automatically pushes your changes
to the remote server whenever you "`fossil commit`".  It also automatically
pulls all remote changes down to your local repository before you
"`fossil update`".

[5]: ./concepts.wiki#workflow

Autosync provides most of the advantages of a centralized version
control system while retaining the advantages of distributed version
control.  Your work stays synced up with your coworkers at all times.
If your local machine dies catastrophically, you haven't lost any
(committed) work.  But you can still work and commit while off network,
with changes resyncing automatically when you get back on-line.

## Syncing Is All-Or-Nothing

Fossil does not support the concept of syncing, pushing, or pulling
individual branches.  When you sync/push/pull in Fossil, you sync/push/pull
everything - all branches, all wiki, all tickets, all forum posts,
all tags, all technotes - everything.

## The Main Branch Is Called "`trunk`", not "`master`"

In Fossil, the traditional name and the default name for the main branch
is "`trunk`".  The "`trunk`" branch in Fossil corresponds to the
"`master`" branch in Git.

These naming conventions are so embedded in each system, that the
"trunk" branch name is automatically translated to "master" when
a [Fossil repo is mirrored to GitHub][6].

[6]: ./mirrortogithub.md

## The "`fossil status`" Command Does Not Show Unmanaged Files

The "`fossil status`" command shows you what files in your check-out have
been edited and scheduled for adding or removing at the next commit.
But unlike "`git status`", the "`fossil status`" command does not warn
you about unmanaged files in your local check-out.  There is a separate
"`fossil extras`" command for that.

## There Is No Rebase

Fossil does not support rebase.
This is a [deliberate design decision][3] that has been thoroughly,
carefully, and throughtfully discussed, many times.  If you are fond
of rebase, you should read the [Rebase Considered Harmful][3] document
carefully before expressing your views.

[3]: ./rebaseharm.md

## Branch and Tag Names

Fossil has no special restrictions on the names of tags and branches,
though you might want to to keep [Git's tag and branch name restrictions][4]
in mind if you plan on mirroring your Fossil repository to GitHub.

[4]: https://git-scm.com/docs/git-check-ref-format

Fossil does not require tag and branch names to be unique.  It is
common, for example, to put a "`release`" tag on every release for a
Fossil-hosted project.

## Only One "origin" At A Time

A Fossil repository only keeps track of one "origin" server at a time.
If you specify a new "origin" it forgets the previous one.  Use the
"`fossil remote`" command to see or change the "origin".

Fossil uses a very different sync protocol than Git, so it isn't as
important for Fossil to keep track of multiple origins as it is with
Git.  So only having a single origin has never been a big enough problem
in Fossil that somebody felt the need to extend it.

Maybe we will add multiple origin support to Fossil someday.  Patches
are welcomed if you want to have a go at it.

## Cherry-pick Is An Option To The "merge" Command

In Git, "`git cherry-pick`" is a separate command.
In Fossil, "`fossil merge --cherrypick`" is an option on the merge
command.  Otherwise, they work mostly the same.

Except, the Fossil file format remembers cherrypicks and actually
shows them as dashed lines on the graphical DAG display, whereas
there is no provision for recording cherry-picks in the Git file
format, so you have to talk about the cherry-pick in the commit
comment if you want to remember it.

## The "`fossil mv`" and "`fossil rm`" Commands Do Not Actually Rename Or Delete The Files (by default)

By default,
the "`fossil mv`" and "`fossil rm`" commands work like they do in CVS in
that they schedule the changes for the next commit, but do not actually
rename or delete the files in your check-out.  You can to add the "--hard"
option to also changes the files in your check-out.
If you run

         fossil setting --global mv-rm-files 1

it makes a notation in your per-user "~/.fossil" settings file so that
the "--hard" behavior becomes the new default.
Changes to www/globs.md.
1
2
3
4
5
6
7
8
9
10

11


12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47


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





60

61


62
63
64









65


66
67

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

119

120
121
122



123
124

125

126
127
128

129
130
131




132
133
134
135
136
137
138
# File Name Glob Patterns


A [glob pattern][glob] is a text expression that matches one or more
file names using wild cards familiar to most users of a command line.
For example, `*` is a glob that matches any name at all and
`Readme.txt` is a glob that matches exactly one file.

Note that although both are notations for describing patterns in text,
glob patterns are not the same thing as a [regular expression or

regexp][regexp].



[glob]: https://en.wikipedia.org/wiki/Glob_(programming) (Wikipedia)

[regexp]: https://en.wikipedia.org/wiki/Regular_expression


A number of fossil setting values hold one or more file glob patterns
that will identify files needing special treatment.  Glob patterns are
also accepted in options to certain commands as well as query
parameters to certain pages.

In many cases more than one glob may be specified in a setting,
option, or query parameter by listing multiple globs separated by a
comma or white space.

Of course, many fossil commands also accept lists of files to act on,
and those also may be specified with globs. Although those glob
patterns are similar to what is described here, they are not defined
by fossil, but rather by the conventions of the operating system in
use.


## Syntax

A list of glob patterns is simply one or more glob patterns separated

by white space or commas. If a glob must contain white spaces or
commas, it can be quoted with either single or double quotation marks.
A list is said to match if any one (or more) globs in the list
matches.

A glob pattern is a collection of characters compared to a target
text, usually a file name. The whole glob is said to match if it
successfully consumes and matches the entire target text. Glob
patterns are made up of ordinary characters and special characters.

Ordinary characters consume a single character of the target and must
match it exactly.



Special characters (and special character sequences) consume zero or
more characters from the target and describe what matches. The special
characters (and sequences) are:

:Pattern |:Effect
---------------------------------------------------------------------
`*`      | Matches any sequence of zero or more characters
`?`      | Matches exactly one character
`[...]`  | Matches one character from the enclosed list of characters
`[^...]` | Matches one character not in the enclosed list






Special character sequences have some additional features:




 *  A range of characters may be specified with `-`, so `[a-d]` matches
    exactly the same characters as `[abcd]`. Ranges reflect Unicode
    code points without any locale-specific collation sequence.









 *  Include `-` in a list by placing it last, just before the `]`.


 *  Include `]` in a list by making the first character after the `[` or
    `[^`. At any other place, `]` ends the list.

 *  Include `^` in a list by placing anywhere except first after the
    `[`.
 *  Beware that ranges in lists may include more than you expect:
    `[A-z]` Matches `A` and `Z`, but also matches `a` and some less
    obvious characters such as `[`, `\`, and `]` with code point
    values between `Z` and `a`.
 *  Beware that a range must be specified from low value to high
    value: `[z-a]` does not match any character at all, preventing the
    entire glob from matching.
 *  Note that unlike typical Unix shell globs, wildcards (`*`, `?`,
    and character lists) are allowed to match `/` directory
    separators as well as the initial `.` in the name of a hidden
    file or directory.

Some examples of character lists:

:Pattern |:Effect
---------------------------------------------------------------------
`[a-d]`  | Matches any one of `a`, `b`, `c`, or `d` but not `ä`
`[^a-d]` | Matches exactly one character other than `a`, `b`, `c`, or `d`
`[0-9a-fA-F]` | Matches exactly one hexadecimal digit
`[a-]`   | Matches either `a` or `-`
`[][]`   | Matches either `]` or `[`
`[^]]`   | Matches exactly one character other than `]`
`[]^]`   | Matches either `]` or `^`
`[^-]`   | Matches exactly one character other than `-`

White space means the specific ASCII characters TAB, LF, VT, FF, CR,
and SPACE.  Note that this does not include any of the many additional
spacing characters available in Unicode, and specifically does not
include U+00A0 NO-BREAK SPACE.

Because both LF and CR are white space and leading and trailing spaces
are stripped from each glob in a list, a list of globs may be broken
into lines between globs when the list is stored in a file (as for a
versioned setting).

Similarly 'single quotes' and "double quotes" are the ASCII straight
quote characters, not any of the other quotation marks provided in
Unicode and specifically not the "curly" quotes preferred by
typesetters and word processors.


## File Names to Match

Before it is compared to a glob pattern, each file name is transformed
to a canonical form. The glob must match the entire canonical file
name to be considered a match.

The canonical name of a file has all directory separators changed to
`/`, redundant slashes are removed, all `.` path components are

removed, and all `..` path components are resolved. (There are

additional details we are ignoring here, but they cover rare edge
cases and also follow the principle of least surprise.)




The goal is to have a name that is the simplest possible for each
particular file, and that will be the same on Windows, Unix, and any

other platform where fossil is run.


Beware, however, that all glob matching is case sensitive. This will
not be a surprise on Unix where all file names are also case

sensitive. However, most Windows file systems are case preserving and
case insensitive. That is, on Windows, the names `ReadMe` and `README`
are names of the same file; on Unix they are different files.





Some example cases:

:Pattern     |:Effect
--------------------------------------------------------------------------------
`README`     | Matches only a file named `README` in the root of the tree. It does not match a file named `src/README` because it does not include any characters that consume (and match) the `src/` part.
`*/README`   | Matches `src/README`. Unlike Unix file globs, it also matches `src/library/README`. However it does not match the file `README` in the root of the tree.








<
|
>
|
>
>

|
>


<
|
|
|
|

<
<
|
|
<
<
|
<
|




|
>


|


|
<
|
<

|
|
>
>

|
<
|






|

>
>
>
>
>
|
>

>
>
|
|

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



<
<
<
<
















|
|



|
|

|








|
<

|
|
>
|
>
|
|

>
>
>

|
>
|
>

|
|
>
|

|
>
>
>
>







1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17
18

19
20
21
22
23


24
25


26

27
28
29
30
31
32
33
34
35
36
37
38
39

40

41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87



88
89
90




91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File Name Glob Patterns


A [glob pattern][glob] is a text expression that matches one or more
file names using wild cards familiar to most users of a command line.
For example, `*` is a glob that matches any name at all and
`Readme.txt` is a glob that matches exactly one file.


A glob should not be confused with a [regular expression][regexp] (RE),
even though they use some of the same special characters for similar
purposes, because [they are not fully compatible][greinc] pattern
matching languages. Fossil uses globs when matching file names with the
settings described in this document, not REs.

[glob]:   https://en.wikipedia.org/wiki/Glob_(programming)
[greinc]: https://unix.stackexchange.com/a/57958/138
[regexp]: https://en.wikipedia.org/wiki/Regular_expression


These settings hold one or more file glob patterns to cause Fossil to
give matching named files special treatment.  Glob patterns are also
accepted in options to certain commands and as query parameters to
certain Fossil UI web pages.



Where Fossil also accepts globs in commands, this handling may interact
with your OS’s command shell or its C runtime system, because they may


have their own glob pattern handling. We will detail such interactions

below.


## Syntax

Where Fossil accepts glob patterns, it will usually accept a *list* of
such patterns, each individual pattern separated from the others
by white space or commas. If a glob must contain white spaces or
commas, it can be quoted with either single or double quotation marks.
A list is said to match if any one glob in the list
matches.

A glob pattern matches a given file name if it successfully consumes and

matches the *entire* name. Partial matches are failed matches.


Most characters in a glob pattern consume a single character of the file
name and must match it exactly. For instance, “a” in a glob simply
matches the letter “a” in the file name unless it is inside a special
character sequence.

Other characters have special meaning, and they may include otherwise

normal characters to give them special meaning:

:Pattern |:Effect
---------------------------------------------------------------------
`*`      | Matches any sequence of zero or more characters
`?`      | Matches exactly one character
`[...]`  | Matches one character from the enclosed list of characters
`[^...]` | Matches one character *not* in the enclosed list

Note that unlike [POSIX globs][pg], these special characters and
sequences are allowed to match `/` directory separators as well as the
initial `.` in the name of a hidden file or directory. This is because
Fossil file names are stored as complete path names. The distinction
between file name and directory name is “below” Fossil in this sense.

[pg]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13

The bracket expresssions above require some additional explanation:

 *  A range of characters may be specified with `-`, so `[a-f]` matches
    exactly the same characters as `[abcdef]`. Ranges reflect Unicode
    code points without any locale-specific collation sequence.
    Therefore, this particular sequence never matches the Unicode
    pre-composed character `é`, for example. (U+00E9)

 *  This dependence on character/code point ordering may have other
    effects to surprise you. For example, the glob `[A-z]` not only
    matches upper and lowercase ASCII letters, it also matches several
    punctuation characters placed between `Z` and `a` in both ASCII and
    Unicode: `[`, `\`, `]`, `^`, `_`, and <tt>\`</tt>.

 *  You may include a literal `-` in a list by placing it last, just
    before the `]`.

 *  You may include a literal `]` in a list by making the first
    character after the `[` or `[^`. At any other place, `]` ends the list.

 *  You may include a literal `^` in a list by placing it anywhere
    except after the opening `[`.




 *  Beware that a range must be specified from low value to high
    value: `[z-a]` does not match any character at all, preventing the
    entire glob from matching.





Some examples of character lists:

:Pattern |:Effect
---------------------------------------------------------------------
`[a-d]`  | Matches any one of `a`, `b`, `c`, or `d` but not `ä`
`[^a-d]` | Matches exactly one character other than `a`, `b`, `c`, or `d`
`[0-9a-fA-F]` | Matches exactly one hexadecimal digit
`[a-]`   | Matches either `a` or `-`
`[][]`   | Matches either `]` or `[`
`[^]]`   | Matches exactly one character other than `]`
`[]^]`   | Matches either `]` or `^`
`[^-]`   | Matches exactly one character other than `-`

White space means the specific ASCII characters TAB, LF, VT, FF, CR,
and SPACE.  Note that this does not include any of the many additional
spacing characters available in Unicode such as
U+00A0, NO-BREAK SPACE.

Because both LF and CR are white space and leading and trailing spaces
are stripped from each glob in a list, a list of globs may be broken
into lines between globs when the list is stored in a file, as for a
versioned setting.

Note that 'single quotes' and "double quotes" are the ASCII straight
quote characters, not any of the other quotation marks provided in
Unicode and specifically not the "curly" quotes preferred by
typesetters and word processors.


## File Names to Match

Before it is compared to a glob pattern, each file name is transformed
to a canonical form:


  *  all directory separators are changed to `/`
  *  redundant slashes are removed
  *  all `.` path components are removed
  *  all `..` path components are resolved

(There are additional details we are ignoring here, but they cover rare
edge cases and follow the principle of least surprise.)

The glob must match the *entire* canonical file name to be considered a
match.

The goal is to have a name that is the simplest possible for each
particular file, and that will be the same regardless of the platform
you run Fossil on. This is important when you have a repository cloned
from multiple platforms and have globs in versioned settings: you want
those settings to be interpreted the same way everywhere.

Beware, however, that all glob matching in Fossil is case sensitive
regardless of host platform and file system. This will not be a surprise
on POSIX platforms where file names are usually treated case
sensitively. However, most Windows file systems are case preserving but
case insensitive. That is, on Windows, the names `ReadMe` and `README`
are usually names of the same file. The same is true in other cases,
such as by default on macOS file systems and in the file system drivers
for Windows file systems running on non-Windows systems. (e.g. exfat on
Linux.) Therefore, write your Fossil glob patterns to match the name of
the file as checked into the repository.

Some example cases:

:Pattern     |:Effect
--------------------------------------------------------------------------------
`README`     | Matches only a file named `README` in the root of the tree. It does not match a file named `src/README` because it does not include any characters that consume (and match) the `src/` part.
`*/README`   | Matches `src/README`. Unlike Unix file globs, it also matches `src/library/README`. However it does not match the file `README` in the root of the tree.
186
187
188
189
190
191
192

193
194
195
196
197
198
199
 *  [`changes`][]
 *  [`clean`][]
 *  [`commit`][]
 *  [`extras`][]
 *  [`merge`][]
 *  [`settings`][]
 *  [`status`][]

 *  [`unset`][]

The commands [`tarball`][] and [`zip`][] produce compressed archives of a
specific checkin. They may be further restricted by options that
specify glob patterns that name files to include or exclude rather
than archiving the entire checkin.








>







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
 *  [`changes`][]
 *  [`clean`][]
 *  [`commit`][]
 *  [`extras`][]
 *  [`merge`][]
 *  [`settings`][]
 *  [`status`][]
 *  [`touch`][]
 *  [`unset`][]

The commands [`tarball`][] and [`zip`][] produce compressed archives of a
specific checkin. They may be further restricted by options that
specify glob patterns that name files to include or exclude rather
than archiving the entire checkin.

207
208
209
210
211
212
213

214
215
216
217
218
219
220
[`changes`]: /help?cmd=changes
[`clean`]: /help?cmd=clean
[`commit`]: /help?cmd=commit
[`extras`]: /help?cmd=extras
[`merge`]: /help?cmd=merge
[`settings`]: /help?cmd=settings
[`status`]: /help?cmd=status

[`unset`]: /help?cmd=unset

[`tarball`]: /help?cmd=tarball
[`zip`]: /help?cmd=zip

[`http`]: /help?cmd=http
[`cgi`]: /help?cmd=cgi







>







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
[`changes`]: /help?cmd=changes
[`clean`]: /help?cmd=clean
[`commit`]: /help?cmd=commit
[`extras`]: /help?cmd=extras
[`merge`]: /help?cmd=merge
[`settings`]: /help?cmd=settings
[`status`]: /help?cmd=status
[`touch`]: /help?cmd=touch
[`unset`]: /help?cmd=unset

[`tarball`]: /help?cmd=tarball
[`zip`]: /help?cmd=zip

[`http`]: /help?cmd=http
[`cgi`]: /help?cmd=cgi
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
settings` commands.

That advice does not help you when you are giving one-off glob patterns
in `fossil` commands. The remainder of this section gives remedies and
workarounds for these problems.


## POSIX Systems

If you are using Fossil on a system with a POSIX-compatible shell
&mdash; Linux, macOS, the BSDs, Unix, Cygwin, WSL etc. &mdash; the shell
may expand the glob patterns before passing the result to the `fossil`
executable.

Sometimes this is exactly what you want.  Consider this command for







|







280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
settings` commands.

That advice does not help you when you are giving one-off glob patterns
in `fossil` commands. The remainder of this section gives remedies and
workarounds for these problems.


### <a name="posix"></a>POSIX Systems

If you are using Fossil on a system with a POSIX-compatible shell
&mdash; Linux, macOS, the BSDs, Unix, Cygwin, WSL etc. &mdash; the shell
may expand the glob patterns before passing the result to the `fossil`
executable.

Sometimes this is exactly what you want.  Consider this command for
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
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
above to make sure the right set of files were scheduled for insertion
into the repository before checking the changes in. You never want to
accidentally check something like a password, an API key, or the
private half of a public cryptographic key into Fossil repository that
can be read by people who should not have such secrets.



















## Windows

Neither standard Windows command shell &mdash; `cmd.exe` or PowerShell
&mdash; expands glob patterns the way POSIX shells do. Windows command
shells rely on the command itself to do the glob pattern expansion. The
way this works depends on several factors:

 *  the version of Windows you are using
 *  which OS upgrades have been applied to it
 *  the compiler that built your Fossil executable
 *  whether you are running the command interactively
 *  whether the command is built against a runtime system that does this
    at all
 *  whether the Fossil command is being run from a file named `*.BAT` vs
    being named `*.CMD`

These factors also affect how a program like `fossil.exe` interprets


quotation marks on its command line.


The fifth item above does not apply to `fossil.exe` when built with
typical tool chains, but we will see an example below where the exception
applies in a way that affects how Fossil interprets the glob pattern.

The most common problem is figuring out how to get a glob pattern passed
on the command line into `fossil.exe` without it being expanded by the C
runtime library that your particular Fossil executable is linked to,
which tries to act like the POSIX systems described above. Windows is
not strongly governed by POSIX, so it has not historically hewed closely
to its strictures.

(This section does not cover the [Microsoft POSIX
subsystem](https://en.wikipedia.org/wiki/Microsoft_POSIX_subsystem),
Windows' obsolete [Services for Unix
3.*x*](https://en.wikipedia.org/wiki/Windows_Services_for_UNIX) feature,
or the [Windows Subsystem for
Linux](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux). (The
latter is sometimes incorrectly called "Bash on Windows" or "Ubuntu on
Windows.") See the POSIX Systems section above for those cases.)

For example, consider how you would set `crlf-glob` to `*` in order to
disable Fossil's "looks like a binary file" checks. The na&iuml;ve

approach will not work:

    C:\...> fossil setting crlf-glob *

The C runtime library will expand that to the list of all files in the
current directory, which will probably cause a Fossil error because
Fossil expects either nothing or option flags after the setting's new
value.



Let's try again:

    C:\...> fossil setting crlf-glob '*'


That may or may not work. Either `'*'` or `*` needs to be passed through







to Fossil untouched for this to do what you expect, which may or may not
happen, depending on the factors listed above.


An approach that *will* work reliably is:

    C:\...> echo * | fossil setting crlf-glob --args -

This works because the built-in command `echo` does not expand its
arguments, and the `--args -` option makes it read further command
arguments from Fossil's standard input, which is connected to the output
of `echo` by the pipe. (`-` is a common Unix convention meaning
"standard input.")









Another (usually) correct approach is:


    C:\...> fossil setting crlf-glob *,

This works because the trailing comma prevents the command shell from
matching any files, unless you happen to have files named with a
trailing comma in the current directory. If the pattern matches no
files, it is passed into Fossil's `main()` function as-is by the C
runtime system. Since Fossil uses commas to separate multiple glob
patterns, this means "all files at the root of the Fossil checkout


directory and nothing else."


















## Converting `.gitignore` to `ignore-glob`

Many other version control systems handle the specific case of
ignoring certain files differently from fossil: they have you create
individual "ignore" files in each folder, which specify things ignored
in that folder and below. Usually some form of glob patterns are used
in those files, but the details differ from fossil.

In many simple cases, you can just store a top level "ignore" file in
`.fossil-settings/ignore-glob`. But as usual, there will be lots of
edge cases.

[Git has a rich collection of ignore files][gitignore] which
accumulate rules that affect the current command. There are global
files, per-user files, per workspace unmanaged files, and fully
version controlled files. Some of the files used have no set name, but
are called out in configuration files.

[gitignore]: https://git-scm.com/docs/gitignore

In contrast, fossil has a global setting and a local setting, but the local setting
overrides the global rather than extending it. Similarly, a fossil
command's `--ignore` option replaces the `ignore-glob` setting rather
than extending it.

With that in mind, translating a `.gitignore` file into
`.fossil-settings/ignore-glob` may be possible in many cases. Here are
some of features of `.gitignore` and comments on how they relate to
fossil:

 *  "A blank line matches no files..." is the same in fossil.
 *  "A line starting with # serves as a comment...." not in fossil.
 *  "Trailing spaces are ignored unless they are quoted..." is similar
    in fossil. All whitespace before and after a glob is trimmed in
    fossil unless quoted with single or double quotes. Git uses
    backslash quoting instead, which fossil does not.
 *  "An optional prefix "!" which negates the pattern..." not in
    fossil.
 *  Git's globs are relative to the location of the `.gitignore` file;
    fossil's globs are relative to the root of the workspace.
 *  Git's globs and fossil's globs treat directory separators
    differently. Git includes a notation for zero or more directories
    that is not needed in fossil.

### Example

In a project with source and documentation:

    work
      +-- doc







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















|
>
>
|
|
>
|
<
<




|



<
<
<
<
<
<
<
<
<

<
>
|






|
>
>





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





|
|
|

|
>

>
>
>
>
>
>
>
|
>



|




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





|


|













|
|






|

|
|

|
|
|
|
|
|
|
|

|







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
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
above to make sure the right set of files were scheduled for insertion
into the repository before checking the changes in. You never want to
accidentally check something like a password, an API key, or the
private half of a public cryptographic key into Fossil repository that
can be read by people who should not have such secrets.


### <a name="windows"></a>Windows

Before we get into Windows-specific details here, beware that this
section does not apply to the several Microsoft Windows extensions that
provide POSIX semantics to Windows, for which you want to use the advice
in [the POSIX section above](#posix) instead:

  *  the ancient and rarely-used [Microsoft POSIX subsystem][mps];
  *  its now-discontinued replacement feature, [Services for Unix][sfu]; or
  *  their modern replacement, the [Windows Subsystem for Linux][wsl]

[mps]: https://en.wikipedia.org/wiki/Microsoft_POSIX_subsystem
[sfu]: https://en.wikipedia.org/wiki/Windows_Services_for_UNIX
[wsl]: https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux

(The latter is sometimes incorrectly called "Bash on Windows" or "Ubuntu
on Windows," but the feature provides much more than just Bash or Ubuntu
for Windows.)

Neither standard Windows command shell &mdash; `cmd.exe` or PowerShell
&mdash; expands glob patterns the way POSIX shells do. Windows command
shells rely on the command itself to do the glob pattern expansion. The
way this works depends on several factors:

 *  the version of Windows you are using
 *  which OS upgrades have been applied to it
 *  the compiler that built your Fossil executable
 *  whether you are running the command interactively
 *  whether the command is built against a runtime system that does this
    at all
 *  whether the Fossil command is being run from a file named `*.BAT` vs
    being named `*.CMD`

Usually (but not always!) the C runtime library that your `fossil.exe`
executable is built against does this glob expansion on Windows so the
program proper does not have to. This may then interact with the way the
Windows command shell you’re using handles argument quoting. Because of
these differences, it is common to find perfectly valid Fossil command
examples that were written and tested on a POSIX system which then fail
when tried on Windows.



The most common problem is figuring out how to get a glob pattern passed
on the command line into `fossil.exe` without it being expanded by the C
runtime library that your particular Fossil executable is linked to,
which tries to act like [the POSIX systems described above](#posix). Windows is
not strongly governed by POSIX, so it has not historically hewed closely
to its strictures.










For example, consider how you would set `crlf-glob` to `*` in order to

get normal Windows text files with CR+LF line endings past Fossil's
"looks like a binary file" check. The na&iuml;ve approach will not work:

    C:\...> fossil setting crlf-glob *

The C runtime library will expand that to the list of all files in the
current directory, which will probably cause a Fossil error because
Fossil expects either nothing or option flags after the setting's new
value, not a list of file names. (To be fair, the same thing will happen
on POSIX systems, only at the shell level, before `.../bin/fossil` even
gets run by the shell.)

Let's try again:

    C:\...> fossil setting crlf-glob '*'

Quoting the argument like that will work reliably on POSIX, but it may
or may not work on Windows. If your Windows command shell interprets the
quotes, it means `fossil.exe` will see only the bare `*` so the C
runtime library it is linked to will likely expand the list of files in
the current directory before the `setting` command gets a chance to
parse the command line arguments, causing the same failure as above.
This alternative only works if you’re using a Windows command shell that
passes the quotes through to the executable *and* you have linked Fossil
to a C runtime library that interprets the quotes properly itself,
resulting in a bare `*` getting clear down to Fossils `setting` command

parser.

An approach that *will* work reliably is:

    C:\...> echo * | fossil setting crlf-glob --args -

This works because the built-in Windows command `echo` does not expand its
arguments, and the `--args -` option makes Fossil read further command
arguments from its standard input, which is connected to the output
of `echo` by the pipe. (`-` is a common Unix convention meaning
"standard input," which Fossil obeys.) A [batch script][fng.cmd] to automate this trick was
posted on the now-inactive Fossil Mailing List.

[fng.cmd]: https://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg25099.html

(Ironically, this method will *not* work on POSIX systems because it is
not up to the command to expand globs. The shell will expand the `*` in
the `echo` command, so the list of file names will be passed to the
`fossil` standard input, just as with the first example above!)

Another (usually) correct approach which will work on both Windows and
POSIX systems:

    C:\...> fossil setting crlf-glob *,

This works because the trailing comma prevents the glob pattern from
matching any files, unless you happen to have files named with a
trailing comma in the current directory. If the pattern matches no
files, it is passed into Fossil's `main()` function as-is by the C
runtime system. Since Fossil uses commas to separate multiple glob
patterns, this means "all files from the root of the Fossil checkout
directory downward and nothing else," which is of course equivalent to
"all managed files in this repository," our original goal.


## Experimenting

To preview the effects of command line glob pattern expansion for
various glob patterns (unquoted, quoted, comma-terminated), for any
combination of command shell, OS, C run time, and Fossil version,
preceed the command you want to test with [`test-echo`][] like so:

    $ fossil test-echo setting crlf-glob "*"
    C:\> echo * | fossil test-echo setting crlf-glob --args -

The [`test-glob`][] command is also handy to test if a string
matches a glob pattern.

[`test-echo`]: /help?cmd=test-echo
[`test-glob`]: /help?cmd=test-glob


## Converting `.gitignore` to `ignore-glob`

Many other version control systems handle the specific case of
ignoring certain files differently from Fossil: they have you create
individual "ignore" files in each folder, which specify things ignored
in that folder and below. Usually some form of glob patterns are used
in those files, but the details differ from Fossil.

In many simple cases, you can just store a top level "ignore" file in
`.fossil-settings/ignore-glob`. But as usual, there will be lots of
edge cases.

[Git has a rich collection of ignore files][gitignore] which
accumulate rules that affect the current command. There are global
files, per-user files, per workspace unmanaged files, and fully
version controlled files. Some of the files used have no set name, but
are called out in configuration files.

[gitignore]: https://git-scm.com/docs/gitignore

In contrast, Fossil has a global setting and a local setting, but the local setting
overrides the global rather than extending it. Similarly, a Fossil
command's `--ignore` option replaces the `ignore-glob` setting rather
than extending it.

With that in mind, translating a `.gitignore` file into
`.fossil-settings/ignore-glob` may be possible in many cases. Here are
some of features of `.gitignore` and comments on how they relate to
Fossil:

 *  "A blank line matches no files...": same in Fossil.
 *  "A line starting with # serves as a comment....": not in Fossil.
 *  "Trailing spaces are ignored unless they are quoted..." is similar
    in Fossil. All whitespace before and after a glob is trimmed in
    Fossil unless quoted with single or double quotes. Git uses
    backslash quoting instead, which Fossil does not.
 *  "An optional prefix "!" which negates the pattern...": not in
    Fossil.
 *  Git's globs are relative to the location of the `.gitignore` file:
    Fossil's globs are relative to the root of the workspace.
 *  Git's globs and Fossil's globs treat directory separators
    differently. Git includes a notation for zero or more directories
    that is not needed in Fossil.

### Example

In a project with source and documentation:

    work
      +-- doc
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523



524


525

526
527
528
529
530
531





## Implementation and References

Most of the implementation of glob pattern handling in fossil is found
`glob.c`, `file.c`, and each individual command and web page that uses
a glob pattern. Find commands and pages in the fossil sources by
looking for comments like `COMMAND: add` or `WEBPAGE: timeline` in
front of the function that implements the command or page in files
`src/*.c`. (Fossil's build system creates the tables used to dispatch
commands at build time by searching the sources for those comments.) A
few starting points:

:File            |:Description
--------------------------------------------------------------------------------
[`src/glob.c`][] | Implementation of glob pattern list loading, parsing, and matching.
[`src/file.c`][] | Implementation of various kinds of canonical names of a file.

[`src/glob.c`]: https://www.fossil-scm.org/index.html/file/src/glob.c
[`src/file.c`]: https://www.fossil-scm.org/index.html/file/src/file.c




The actual pattern matching is implemented in SQL, so the


documentation for `GLOB` and the other string matching operators in

[SQLite] (https://sqlite.org/lang_expr.html#like) is useful. Of
course, the SQLite [source code]
(https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768)
and [test harnesses]
(https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673)
also make entertaining reading.







|
<
<
<
<
<
<
<



|
|




>
>
>
|
>
>
|
>
|
<
|
<
|
<
569
570
571
572
573
574
575
576







577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594

595

596






## Implementation and References

The implementation of the Fossil-specific glob pattern handling is here:








:File            |:Description
--------------------------------------------------------------------------------
[`src/glob.c`][] | pattern list loading, parsing, and generic matching code
[`src/file.c`][] | application of glob patterns to file names

[`src/glob.c`]: https://www.fossil-scm.org/index.html/file/src/glob.c
[`src/file.c`]: https://www.fossil-scm.org/index.html/file/src/file.c

See the [Adding Features to Fossil][aff] document for broader details
about finding and working with such code.

The actual pattern matching leverages the `GLOB` operator in SQLite, so
you may find [its documentation][gdoc], [source code][gsrc] and [test
harness][gtst] helpful.

[aff]:  ./adding_code.wiki
[gdoc]: https://sqlite.org/lang_expr.html#like

[gsrc]: https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768

[gtst]: https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673

Changes to www/grep.md.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    number in `fossil grep` output.

*   There is no way to suppress all output, returning only a status code
    to indicate whether the pattern matched, as with `grep -q`.

*   There is no way to suppress error output, as with `grep -s`.

*   Fossil `grep` accepts only a single input file name. You cannot give
    it a list of file names, and you cannot give it a directory name for
    Fossil to expand to the set of all files under that directory. This
    means Fossil `grep` has no equivalent of the common POSIX `grep -R`
    extension. (And if it did, it would probably have a different option
    letter, since `-R` in Fossil has a different meaning, by
    convention.)

*   You cannot invert the match, as with `grep -v`.

Patches to remove those limitations will be thoughtfully considered.









|
<
|
|
|
|







37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52
53
54
55
    number in `fossil grep` output.

*   There is no way to suppress all output, returning only a status code
    to indicate whether the pattern matched, as with `grep -q`.

*   There is no way to suppress error output, as with `grep -s`.

*   Fossil `grep` does not accept a directory name for Fossil to

    expand to the set of all files under that directory. This means
    Fossil `grep` has no equivalent of the common POSIX `grep -R`
    extension. (And if it did, it would probably have a different
    option letter, since `-R` in Fossil has a different meaning, by
    convention.)

*   You cannot invert the match, as with `grep -v`.

Patches to remove those limitations will be thoughtfully considered.


Changes to www/hacker-howto.wiki.
1
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
<title>Fossil Hackers How-To</title>

The following links are of interest to programmers who want to modify
or enhance Fossil.  Ordinary users can safely ignore this information.

  *  [./build.wiki | How To Compile And Install Fossil]
  *  [./customskin.md | Theming Fossil]

  *  [./makefile.wiki | The Fossil Build Process]
  *  [./tech_overview.wiki | A Technical Overview of Fossil]
  *  [./adding_code.wiki | Adding Features To Fossil]
  *  [./contribute.wiki|Contributing Code Or Enhancements To The Fossil Project]
  *  [./fileformat.wiki|Fossil Artifact File Format]
  *  [./sync.wiki|The Sync Protocol]
  *  [./style.wiki | Coding Style Guidelines]
  *  [./checkin.wiki | Pre-checkin Checklist]
  *  [../test/release-checklist.wiki | Release Checklist]
  *  [./backoffice.md | The "backoffice" subsystem]
|


|



>


<







1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
<title>Fossil Developer How-To</title>

The following links are of interest to programmers who want to modify
or enhance Fossil itself.  Ordinary users can safely ignore this information.

  *  [./build.wiki | How To Compile And Install Fossil]
  *  [./customskin.md | Theming Fossil]
  *  [./adding_code.wiki#newcmd | Adding New Commands To Fossil]
  *  [./makefile.wiki | The Fossil Build Process]
  *  [./tech_overview.wiki | A Technical Overview of Fossil]

  *  [./contribute.wiki|Contributing Code Or Enhancements To The Fossil Project]
  *  [./fileformat.wiki|Fossil Artifact File Format]
  *  [./sync.wiki|The Sync Protocol]
  *  [./style.wiki | Coding Style Guidelines]
  *  [./checkin.wiki | Pre-checkin Checklist]
  *  [../test/release-checklist.wiki | Release Checklist]
  *  [./backoffice.md | The "backoffice" subsystem]
Changes to www/hashpolicy.wiki.
1
2
3
4
5
6
7
8
9
10
11

12

13



14
15
16
17
18
19
20
21
<title>Hash Policy</title>

<h2>Executive Summary</h2>

<b>Or: How To Avoid Reading This Article</b>

There was much angst over the [http://www.shattered.io|SHAttered attack]
against SHA1 when it was announced in early 2017.  If you are concerned
about this and its implications for Fossil, simply
[./quickstart.wiki#install|upgrade to Fossil 2.1 or later], and the
problem will go away.  Everything will continue to work as before.  All

of your legacy repositories will continue to work, and all of your old

check-ins will still have the same name.  Your workflow will be



unchanged.

But if you are curious and want a deeper understanding of what is
going on, read on...


<h2>Introduction</h2>











|
>
|
>
|
>
>
>
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<title>Hash Policy</title>

<h2>Executive Summary</h2>

<b>Or: How To Avoid Reading This Article</b>

There was much angst over the [http://www.shattered.io|SHAttered attack]
against SHA1 when it was announced in early 2017.  If you are concerned
about this and its implications for Fossil, simply
[./quickstart.wiki#install|upgrade to Fossil 2.1 or later], and the
problem will go away.  Everything will continue to work as before.

  *  Legacy repositories will continue working just as
     they always have, without any conversions or upgrades.
  *  Historical check-ins will keep their same historical
     SHA1 names.
  *  New check-ins will get more secure SHA3-256 hash names.
  *  Everything will continue as if nothing happened.
  *  Your workflow will be unchanged.

But if you are curious and want a deeper understanding of what is
going on, read on...


<h2>Introduction</h2>

73
74
75
76
77
78
79










80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

130
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172
173






174
175
176
177
178
179
180
181
Version 2.0 extended the [./fileformat.wiki|Fossil file format]
to allow artifacts to be named by either SHA1 or SHA3-256 hashes.
(SHA3-256 is the only variant of SHA3 that
Fossil uses for artifact naming, so for the remainder of this article
it will be called simply "SHA3".  Similarly, "Hardened SHA1" will
shortened to "SHA1" in the remaining text.)











Other than permitting the use of SHA3 in addition to SHA1, there
were no file format changes in Fossil version 2.0 relative
to the previous version 1.37.  Both Fossil 2.0 and Fossil 1.37 read
and write all the same repositories and sync with one another, as long
as none of the repositories contain artifacts named using SHA3.  If
a repository does contain artifacts named using SHA3, Fossil 1.37 will
not know how to interpret those artifacts and will generate various warnings
and errors.

<h2>How Fossil Decides Which Hash Algorithm To Use</h2>

If newer versions of Fossil are able to use either SHA1 or SHA3 to
name artifacts, which hash algorithm is actually used?  That question
is answered by the "hash policy".  These are the supported hash policies:

<table cellpadding=10>
<tr>
<td valign='top'>sha1</td>
<td>Name all new artifacts using the (Hardened) SHA1 hash algorithm.</td>
</tr>
<tr>
<td valign='top'>auto</td>
<td>Name new artifacts using the SHA1 hash algorithm.  But if any
artifacts are encountered which are already named using SHA3, then
automatically switch the hash policy to "sha3"</td>
</tr>
<tr>
<td valign='top'>sha3</td>
<td>Name new artifacts using the SHA3 hash algorithm if the artifact
does not already have a SHA1 name.  If the artifact already has a SHA1
name, then continue to use the older SHA1 name.  Use SHA3 for new
artifacts that have never before been encountered.</td>
</tr>
<tr>
<td valign='top'>sha3-only</td>
<td>Name new artifacts using the SHA3 hash algorithm even if the artifact
already has a SHA1 name.  In other words, force the use of SHA3.  This can
cause some artifacts to be added to the repository twice, once under their
SHA1 name and again under their SHA3 name.  But delta compression will
prevent that from causing repository size problems.</td>
</tr>
<tr>
<td valign='top'>shun-sha1</td>
<td>Like "sha3-only" but at this level do not accept a push of SHA1-named
artifacts.  If another Fossil instance tries to push a SHA1-named artifact,
that artifact is discarded and ignored.
</tr>
</table>

For Fossil 2.0, and obviously also for Fossil 1.37 and before, the

only hash policy supported was "sha1".  All new artifacts were named
using their SHA1 hash.
Even though Fossil 2.0 was capable of understanding SHA3 hashes, it
never actually generates any SHA3 hashes.

Beginning with Fossil 2.1, the default hash policy for legacy repositories
changed to "auto".
That means Fossil 2.1 will continue to generate only SHA1 hashes until it
encounters one artifact with a SHA3 hash.  Once a single SHA3 hash is

seen, Fossil automatically switches to "sha3" mode and thereafter generates
only SHA3 hashes.

When a new repository is created by cloning, the hash policy is copied
from the parent.

For new repositories created using the
[/help?cmd=new|fossil new] command the default hash policy is "sha3".
That means new repositories
will normally hold nothing except SHA3 hashes.  The hash policy for new
repositories can be overridden using the "--sha1" option to the
"fossil new" command.

Even after upgrading to Fossil 2.1, Fossil will continue to use nothing
but SHA1 hashes on legacy repositories, thus preserving complete
compatibility with Fossil 1.37 and before.  If you want Fossil to go
ahead and start using SHA3 hashes, change the hash policy to
"sha3" using a command like this:

<blockquote><verbatim>
fossil hash-policy sha3
</verbatim></blockquote>

The next check-in will use a SHA3 hash.  And when that check-in is pushed
to colleagues, their copies of Fossil will see the new SHA3-named artifact
and automatically convert to SHA3 as well.


Of course, if some members of your team stubbornly refuse to upgrade past
Fossil 1.37, you should avoid changing the hash policy and creating
artifacts with SHA3 names, because once you do that your recalcitrant
coworkers will no longer be able to collaborate.

<h2>A Pure SHA3 Future</h2>

Fossil 2.10 will change the default hash policy to "sha3" mode. We






decided to make the change since the last known distributor of Fossil
1.x binaries — Debian 9 — was finally replaced in June 2019 by a newer
version distributing Fossil 2.x. All other known sources of Fossil 1.x
binaries upgraded well before that point.

Because Fossil 2.x tends to silently upgrade existing repos to SHA-3
mode unless carefully forced not to, you probably won't even notice the
change.







>
>
>
>
>
>
>
>
>
>









|












|















|











>
|
|
|


|
|
|
|
>
|












<
<
|







|
|
|
>








|
>
>
>
>
>
>
|
|
|
|
<
<
<
<
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168


169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199




Version 2.0 extended the [./fileformat.wiki|Fossil file format]
to allow artifacts to be named by either SHA1 or SHA3-256 hashes.
(SHA3-256 is the only variant of SHA3 that
Fossil uses for artifact naming, so for the remainder of this article
it will be called simply "SHA3".  Similarly, "Hardened SHA1" will
shortened to "SHA1" in the remaining text.)

To be clear: Fossil (version 2.0 and later)
allows the SHA1 and SHA3 hashes to be mixed within
the same repository.  Older check-ins, created years ago,
continue to be named using their legacy SHA1 hashes while
newer check-ins are named using modern SHA3 hashes.  There
is no need to "convert" a repository from SHA1 over to SHA3.
You can see this in Fossil itself.  The recent
[9d9ef82234f63758] check-in uses a SHA3 hash whereas the older
[1669115ab9d05c18] check-in uses a SHA1 hash.

Other than permitting the use of SHA3 in addition to SHA1, there
were no file format changes in Fossil version 2.0 relative
to the previous version 1.37.  Both Fossil 2.0 and Fossil 1.37 read
and write all the same repositories and sync with one another, as long
as none of the repositories contain artifacts named using SHA3.  If
a repository does contain artifacts named using SHA3, Fossil 1.37 will
not know how to interpret those artifacts and will generate various warnings
and errors.

<h2>How Fossil Decides Which Hash Algorithm To Use For New Artifacts</h2>

If newer versions of Fossil are able to use either SHA1 or SHA3 to
name artifacts, which hash algorithm is actually used?  That question
is answered by the "hash policy".  These are the supported hash policies:

<table cellpadding=10>
<tr>
<td valign='top'>sha1</td>
<td>Name all new artifacts using the (Hardened) SHA1 hash algorithm.</td>
</tr>
<tr>
<td valign='top'>auto</td>
<td>Name new artifacts using the SHA1 hash algorithm, but if any
artifacts are encountered which are already named using SHA3, then
automatically switch the hash policy to "sha3"</td>
</tr>
<tr>
<td valign='top'>sha3</td>
<td>Name new artifacts using the SHA3 hash algorithm if the artifact
does not already have a SHA1 name.  If the artifact already has a SHA1
name, then continue to use the older SHA1 name.  Use SHA3 for new
artifacts that have never before been encountered.</td>
</tr>
<tr>
<td valign='top'>sha3-only</td>
<td>Name new artifacts using the SHA3 hash algorithm even if the artifact
already has a SHA1 name.  In other words, force the use of SHA3.  This can
cause some artifacts to be added to the repository twice, once under their
SHA1 name and again under their SHA3 name, but delta compression will
prevent that from causing repository size problems.</td>
</tr>
<tr>
<td valign='top'>shun-sha1</td>
<td>Like "sha3-only" but at this level do not accept a push of SHA1-named
artifacts.  If another Fossil instance tries to push a SHA1-named artifact,
that artifact is discarded and ignored.
</tr>
</table>

For Fossil 2.0, and obviously also for Fossil 1.37 and before, the
only hash policy supported was the one now called "sha1", meaning that
all new artifacts were named
using a SHA1 hash.
Even though Fossil 2.0 added the capability of understanding SHA3 hashes, it
never actually generates any SHA3 hashes.

From Fossil 2.1 through 2.9, the default hash policy for legacy repositories
changed to "auto", meaning that
Fossil continued to generate only SHA1 hashes until it
encountered one artifact with a SHA3 hash.  Once those older versions of
Fossil saw a single SHA3 hash, they
automatically switched to "sha3" mode and thereafter generated
only SHA3 hashes.

When a new repository is created by cloning, the hash policy is copied
from the parent.

For new repositories created using the
[/help?cmd=new|fossil new] command the default hash policy is "sha3".
That means new repositories
will normally hold nothing except SHA3 hashes.  The hash policy for new
repositories can be overridden using the "--sha1" option to the
"fossil new" command.



If you are still on Fossil 2.1 through 2.9 but you want Fossil to go
ahead and start using SHA3 hashes, change the hash policy to
"sha3" using a command like this:

<blockquote><verbatim>
fossil hash-policy sha3
</verbatim></blockquote>

The next check-in will use a SHA3 hash, so that when that check-in is pushed
to colleagues, their clones will include the new SHA3-named artifact, so
their local Fossil instances will automatically convert their clones to
"sha3" mode as well.

Of course, if some members of your team stubbornly refuse to upgrade past
Fossil 1.37, you should avoid changing the hash policy and creating
artifacts with SHA3 names, because once you do that your recalcitrant
coworkers will no longer be able to collaborate.

<h2>A Pure SHA3 Future</h2>

Fossil 2.10 changed the default hash policy to "sha3" mode even for
legacy repositories, so if you
upgrade to the latest version of Fossil, all of your new artifacts will
use a SHA3 hash.  Legacy SHA1 artifacts continue to use their original
names, but new artifacts will use SHA3 names. You might not even notice
this automatic change over to stronger hashes.

We decided to make the change to pure SHA3 since the last known distributor 
of Fossil 1.x binaries — Debian 9 — was finally replaced in June 2019 
by Debian 10, which included Fossil 2.8. All other known sources of 
Fossil 1.x binaries upgraded well before that point.




Added www/history.md.






























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# The History And Purpose Of Fossil

Fossil is a [distributed version control system (DVCS)][100] written
beginning in [2007][105] by the [architect of SQLite][110] for the
purpose of managing the [SQLite project][115].

[100]: https://en.wikipedia.org/wiki/Distributed_version_control
[105]: /timeline?a=1970-01-01&n=10
[110]: https://sqlite.org/crew.html
[115]: https://sqlite.org/

Though Fossil was originally written specifically to support SQLite,
it is now also used by countless other projects.  The SQLite architect (drh)
is still the top committer to Fossil, but there are also
[many other contributors][120].

[120]: /reports?type=ci&view=byuser

## History

The SQLite project start out using [CVS][300], as CVS was the most
commonly used version control system in that era (circa 2000).  CVS
was an amazing version control system for its day in that it allowed
multiple developers to be editing the same file at the same time.

[300]: https://en.wikipedia.org/wiki/Concurrent_Versions_System

Though innovative and much loved in its time, CVS was not without problems.
Among those was a lack of visibility into the project history and the
lack of integrated bug tracking.  To try to address these deficiencies,
the SQLite author developed the [CVSTrac][305] wrapper for CVS beginning
in [2002][310].

[305]: http://cvstrac.org/
[310]: http://cvstrac.org/fossil/timeline?a=19700101&n=10

CVSTrac greatly improved the usability of CVS and was adopted by
other projects.  CVSTrac also [inspired the design][315] of [Trac][320],
which was a similar system that was (and is) far more widely used.

[315]: https://trac.edgewall.org/wiki/TracHistory
[320]: https://trac.edgewall.org/

Historians can see the influence of CVSTrac on the development of
SQLite.  [Early SQLite check-ins][325] that happened before CVSTrac
often had a check-in comment that was just a "smiley".
That was not an unreasonable check-in comment, as check-in comments
were scarcely seen and of questionable utility in raw CVS.  CVSTrac
changed that, making check-in comments more visible and more useful.
The SQLite developers reacted by creating [better check-in comments][330].

[325]: https://sqlite.org/src/timeline?a=19700101&n=10
[330]: https://sqlite.org/src/timeline?c=20030101&n=10&nd

At about this same time, the [Monotone][335] system appeared.
Monotone was one of the first distributed version control systems. As far as
this author is aware, Monotone was the first VCS to make use of
SHA1 to identify artifacts.  Monotone stored its content in an SQLite
database, which is what brought it to the attention of the SQLite architect.
These design choices were a major source of inspiration for Fossil.

[335]: https://www.monotone.ca/

Beginning around 2005, the need for a better version control system
for SQLite began to become evident.  The SQLite architect looked
around for a suitable replacement.  Monotone, Git, and Mercurical were
all considered.  But at that time, none of these supported sync
over ordinary HTTP, none could be run from an inexpensive shell
account on a leased server (this was before the widespread availability
of affordable virtual machines), and none of them supported anything 
resembling the wiki and ticket features of CVSTrac that had been 
found to be so useful.  And so, the SQLite architect began writing
his own DVCS.

Early prototypes were done in [TCL][340].  As experiments proceeded,
however, it was found that the low-level byte manipulates needed for
things like delta compression and computing diffs
were better implemented in plain old C.
Experiments continued.  Finally, a prototype capable of self-hosting
was devised on [2007-07-16][345].

[340]: https://www.tcl.tk/
[345]: https://fossil-scm.org/fossil/timeline?c=200707211410&n=10

The first project hosted by Fossil was Fossil itself.  After a
few months of development work, the code was considered stable enough
to begin hosting the [SQLite documentation repository][350] which was
split off from the main SQLite CVS repository on [2007-11-12][355].
After two years of development work on Fossil, the
SQLite source code itself was transfered to Fossil on
[2009-08-11][360].

[350]: https://www.sqlite.org/docsrc/doc/trunk/README.md
[355]: https://www.sqlite.org/docsrc/timeline?c=200711120345&n=10
[360]: https://sqlite.org/src/timeline?c=b0848925babde524&n=12&y=ci
Changes to www/index.wiki.
1
2
3
4
5
6
7
8
9
10
11
12


13
14
15
16
17
18
19
20
21
22
23
24
25
<title>Home</title>

<h3>What Is Fossil?</h3>

<div style='width:200px;float:right;border:2px solid #446979;padding:10px;margin:0px 10px;'>
<ul>
<li> [/uv/download.html | Download]
<li> [./quickstart.wiki | Quick Start]
<li> [./build.wiki | Install]
<li> [../COPYRIGHT-BSD2.txt | License]
<li> [./faq.wiki | FAQ]
<li> [./changes.wiki | Change Log]


<li> [./hacker-howto.wiki | Hacker How-To]
<li> [./fossil-v-git.wiki | Fossil vs. Git]
<li> [./hints.wiki | Tip &amp; Hints]
<li> [./permutedindex.html | Documentation Index]
<li> [https://fossil-scm.org/forum | Forum ]
<li> [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | Mailing list archives]
</ul>
<img src="fossil3.gif" align="center">
</div>

<p>Fossil is a simple, high-reliability, distributed software configuration
management system with these advanced features:










|
|

>
>


<

<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

17


18
19
20
21
22
23
24
<title>Home</title>

<h3>What Is Fossil?</h3>

<div style='width:200px;float:right;border:2px solid #446979;padding:10px;margin:0px 10px;'>
<ul>
<li> [/uv/download.html | Download]
<li> [./quickstart.wiki | Quick Start]
<li> [./build.wiki | Install]
<li> [https://fossil-scm.org/forum | Support/Forum ]
<li> [./hints.wiki | Tips &amp; Hints]
<li> [./changes.wiki | Change Log]
<li> [../COPYRIGHT-BSD2.txt | License]
<li> [./userlinks.wiki | User inks]
<li> [./hacker-howto.wiki | Hacker How-To]
<li> [./fossil-v-git.wiki | Fossil vs. Git]

<li> [./permutedindex.html | Documentation Index]


</ul>
<img src="fossil3.gif" align="center">
</div>

<p>Fossil is a simple, high-reliability, distributed software configuration
management system with these advanced features:

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145
146
147

148
149
150
151
152
153
154
155




156
      atomic even if interrupted by a power loss or system crash.
      Automatic [./selfcheck.wiki | self-checks] verify that all aspects of
      the repository are consistent prior to each commit.

  8.  <b>Free and Open-Source</b> - Uses the [../COPYRIGHT-BSD2.txt|2-clause BSD license].

<hr>
<h3>Links For Fossil Users:</h3>

  *  [./permutedindex.html | Documentation index] with [/search?c=d | full text search].
  *  [./reviews.wiki | Testimonials] from satisfied Fossil users and
     [./quotes.wiki | Quotes] about Fossil and other DVCSes.
  *  [./faq.wiki | Frequently Asked Questions]
  *  The [./concepts.wiki | concepts] behind Fossil.
     [./whyusefossil.wiki#definitions | Another viewpoint].
  *  [./quickstart.wiki | Quick Start] guide to using Fossil.
  *  [./qandc.wiki | Questions &amp; Criticisms] directed at Fossil.
  *  [./build.wiki | Compiling and Installing]
  *  Fossil supports [./embeddeddoc.wiki | embedded documentation]
     that is versioned along with project source code.
  *  Fossil uses an [./fileformat.wiki | enduring file format] that is
     designed to be readable, searchable, and extensible by people
     not yet born.
  *  A tutorial on [./branching.wiki | branching], what it means and how
     to do it using Fossil.
  *  The [./selfcheck.wiki | automatic self-check] mechanism
     helps insure project integrity.
  *  Fossil contains a [./wikitheory.wiki | built-in wiki].
  *  An [./event.wiki | Event] is a special kind of wiki page associated
     with a point in time rather than a name.
  *  [./settings.wiki | Settings] control the behaviour of Fossil.
  *  [./ssl.wiki | Use SSL] to encrypt communication with the server.
  *  There is a
     [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list]
     (with publicly readable
     [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives])
     available for discussing Fossil issues.
  *  [./stats.wiki | Performance statistics] taken from real-world projects
     hosted on Fossil.
  *  How to [./shunning.wiki | delete content] from a Fossil repository.
  *  How Fossil does [./password.wiki | password management].
  *  On-line [/help | help].
  *  Documentation on the
     [http://www.sqliteconcepts.org/THManual.pdf | TH1 scripting language],
     used to customize [./custom_ticket.wiki | ticketing], and several other
     subsystems, including [./customskin.md | theming].
  *  List of [./th1.md | TH1 commands provided by Fossil itself] that expose
     its key functionality to TH1 scripts.
  *  List of [./th1-hooks.md | TH1 hooks exposed by Fossil] that enable
     customization of commands and web pages.
  *  A free hosting server for Fossil repositories is available at
     [http://chiselapp.com/].
  *  How to [./server/ | set up a server] for your repository.
  *  Customizing the [./custom_ticket.wiki | ticket system].
  *  Methods to [./checkin_names.wiki | identify a specific check-in].
  *  [./inout.wiki | Import and export] from and to Git.
  *  [./fossil-v-git.wiki | Fossil versus Git].
  *  [./fiveminutes.wiki | Up and running in 5 minutes as a single user]
     (contributed by Gilles Ganault on 2013-01-08).
  *  [./antibot.wiki | How Fossil defends against abuse by spiders and bots].


<h3>Links For Fossil Developers:</h3>

  *  [./contribute.wiki | Contributing] code or documentation to the
     Fossil project.
  *  [./theory1.wiki | Thoughts On The Design Of Fossil].

  *  [./pop.wiki | Principles Of Operation]
  *  [./tech_overview.wiki | A Technical Overview Of Fossil].
  *  The [./fileformat.wiki | file format] used by every content
     file stored in the repository.
  *  The [./delta_format.wiki | format of deltas] used to
     efficiently store changes between file revisions.
  *  The [./delta_encoder_algorithm.wiki | encoder algorithm] used to
     efficiently generate deltas.




  *  The [./sync.wiki | synchronization protocol].







|

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

>
|

<
<
<
>
|
|
<
|
<
<
<
<
>
>
>
>
|
81
82
83
84
85
86
87
88
89























90























91



92
93
94
95



96
97
98

99




100
101
102
103
104
      atomic even if interrupted by a power loss or system crash.
      Automatic [./selfcheck.wiki | self-checks] verify that all aspects of
      the repository are consistent prior to each commit.

  8.  <b>Free and Open-Source</b> - Uses the [../COPYRIGHT-BSD2.txt|2-clause BSD license].

<hr>
<h3>Latest Release: 2.10 (2019-10-04)</h3>
























  *  [/uv/download.html|Download]























  *  [./changes.wiki#v2_10|Change Summary]




<hr>
<h3>Quick Start</h3>




  1.  [/uv/download.html|Download] or install using a package manager or
      [./build.wiki|compile from sources].
  2.  <tt>fossil init</tt> <i>new-repository</i>

  3.  <tt>fossil open</tt> <i>new-repository</i>




  4.  <tt>fossil add</tt> <i>files-or-directories</i>
  5.  <tt>fossil commit -m</tt> "<i>commit message</i>"
  6.  <tt>fossil ui</tt>
  7.  Repeat steps 4, 5, and 6, in any order, as necessary.
      See the [./quickstart.wiki|Quick Start Guide] for more detail.
Changes to www/javascript.md.
176
177
178
179
180
181
182















183
184
185
186
187
188
189
_Workaround:_ Edit the URL to give the “`ln`” query parameter per [the
`/file` docs](/help?cmd=/file), or provide a patch to reload the page
with this parameter included/excluded to implement the toggle via a
server round-trip.

[mainc]: https://fossil-scm.org/fossil/artifact?ln&name=87d67e745

















### <a id="sort"></a>Table Sorting

On pages showing a data table, the column headers may be clickable to do
a client-side sort of the data on that column.

_Potential Workaround:_ This feature could be enhanced to do the sort on







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







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
_Workaround:_ Edit the URL to give the “`ln`” query parameter per [the
`/file` docs](/help?cmd=/file), or provide a patch to reload the page
with this parameter included/excluded to implement the toggle via a
server round-trip.

[mainc]: https://fossil-scm.org/fossil/artifact?ln&name=87d67e745


### <a id="sxsdiff"></a>Side-by-Side Diff Mode

The default “diff” view is a side-by-side mode. If either of the boxes
of output — the “from” and “to” versions of the repo contents for that
check-in — requires a horizontal scroll bar given the box content, font
size, browser window width, etc., both boxes will usually end up needing
to scroll since they should contain roughly similar content. Fossil
therefore scrolls both boxes when you drag the scroll bar on one because
if you want to examine part of a line scrolled out of the HTML element
in one box, you probably want to examine the same point on that line in
the other box.

_Graceful Fallback:_ Manually scroll both boxes to sync their views.


### <a id="sort"></a>Table Sorting

On pages showing a data table, the column headers may be clickable to do
a client-side sort of the data on that column.

_Potential Workaround:_ This feature could be enhanced to do the sort on
Added www/json-api/_template.md.












































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# JSON API: X
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Foo](#foo)
* [Bar](#bar)
* [Baz](#baz)

---

<a id="foo"></a>
# Foo

<a id="bar"></a>
# Bar

<a id="baz"></a>
# Baz


# Footnotes
Added www/json-api/api-artifact.md.


















































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# JSON API: /artifact
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Checkin Artifacts (Commits)](#checkin)
* [File Artifacts](#file)
* [Wiki Artifacts](#wiki)

---

<a id="checkin"></a>
# Checkin Artifacts (Commits)

Returns information about checkin artifacts (commits).

**Status:** implemented 201110xx

**Request:** `/json/artifact/COMMIT_UUID`

**Required permissions:** "o" (was "h" prior to 20120408)

**Response payload example: (CHANGED SIGNIFICANTLY ON 20120713)**

```json
{
"type":"checkin",
"name":"18dd383e5e7684e", // as given on CLI
"uuid":"18dd383e5e7684ecee327d3de7d3ff846069d1b2",
"isLeaf":false,
"user":"drh",
"comment":"Merge wideAnnotateUser and jsonWarnings into trunk.",
"timestamp":1330090810,
"parents":[
  // 1st entry is primary parent UUID:
  "3a44f95f40a193739aaafc2409f155df43e74a6f",
  // Remaining entries are merged-in branch UUIDs:
  "86f6e675eb3f8761d70d8b82b052ce2b297fffd2",\
  "dbf4ecf414881c9aad6f4f125dab9762589ef3d7"\
],
"tags":["trunk"],
"files":[{
    "name":"src/diff.c",
    // BLOB uuids, NOT commit UUIDs:
    "uuid":"78c74c3b37e266f8f7e570d5cf476854b7af9d76",
    "parent":"b1fa7e636cf4e7b6ed20bba2d2680397f80c096a",
    "state":"modified",
    "downloadPath":"/raw/src/diff.c?name=78c74c3b37e266f8f7e570d5cf476854b7af9d76"
  },
  ...]
}
```

The "parents" property lists the parent UUIDs of the checkin. The
"parent" property of file entries refers to the parent UUID of that
file. In the case of a merge there may be essentially an arbitrary
number. The first entry in the list is the "primary" parent. The primary
parent is the parent which was not pulled in via a merge operation. The
ordering of remaining entries is unspecified and may even change between
calls. For example: if, from branch C, we merge in A and B and then
commit, then in the artifact response for that commit the UUID of branch
C will be in the first (primary) position, with the UUIDs for branches A
and B in the following entries (in an unspecified, and possibly
unstable, order).

Note that the "uuid" and "parent" properties of the "files" entries
refer to raw blob uuids, not commit uuids (i.e. not checkins).

<a id="file"></a>
# File Artifacts

Fetches information about file artifacts.

**FIXME:** the content type guessing is currently very primitive, and
may (but i haven't seen this) mis-diagnose some non-binary files as
binary. Fossil doesn't yet have a mechanism for mime-type mappings.

**Status:** implemented 20111020

**Required permissions:** "o"

**Request:** `/json/artifact/FILE_UUID`

**Request options:**

-   `format=(raw|html|none)` (default=none). If set, the contents of the
    artifact are included if they are text, else they are not (JSON does
    not do binary). The "html" flag runs it through the wiki parser. The
    results of doing so are unspecified for non-embedded-doc files. The
    "raw" format means to return the content as-is. "none" is the same
    as not specifying this flag, and elides the content from the
    response.
-   DEPRECATED (use format instead): `includeContent=bool` (=false) (CLI:
    `--content|-c`). If true, the full content of the artifact is returned
    for text-only artifacts (but not for non-text artifacts). As of
    20120713 this option is only inspected if "format" is not specified.

**Response payload example: (CHANGED SIGNIFICANTLY ON 20120713)**

```json
{
"type":"file",
"name":"same name specified as FILE_UUID argument",
"size": 12345, // in bytes, independent of format=...
"parent": "uuid of parent file blob. Not set for first generation.",
"checkins":[{
  "name":"src/json_detail.h",
  "timestamp":1319058803,
  "comment":"...",
  "user":"stephan",
  "checkin":"d2c1ae23a90b24f6ca1d7637193a59d5ecf3e680",
  "branch":"json",
  "state":"added|modified|removed"
  },
  ...],
/* The following "content" properties are only set if format=raw|html */
"content": "file contents",
"contentSize": "size of content field, in bytes. Affected by the format option!",
"contentType": "text/plain", /* currently always text/plain */
"contentFormat": "html|raw"
}
```

The "checkins" array lists all checkins which include this file, and a
file might have different names across different branches. The size and
uuid, however, are the same across all checkins for a given blob.

<a id="wiki"></a>
# Wiki Artifacts

Returns information about wiki artifacts.

**Status:** implemented 20111020, fixed to return the requested version
(instead of the latest) on 20120302.

**Request:** `/json/artifact/WIKI_UUID`

**Required permissions:** "j"

**Options:**

-   DEPRECATED (use format instead): `bool includeContent` (=false). If
    true then the raw content is returned with the wiki page, else no
    content is returned.\  
    CLI: `--includeContent|-c`
-   The `--format` option works as for
    [`/json/wiki/get`](api-wiki.md#get), and if set then it
    implies the `includeContent` option.

**Response payload example:**

Currently the same as [`/json/wiki/get`](api-wiki.md#get).

Added www/json-api/api-auth.md.






























































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# JSON API: X
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Introduction](#intro)
* [Capabilities (Access Rights)](#capabilities)
* [Login](#login)
    * [Anonymous User Logins](#login-anonymous)
* [Logout](#logout)
* [Whoami](#whoami)

---

<a id="intro"></a>
# Introduction

**FIXME:** Ross found a bug:
[](/info/479aadb1d2645601)
(sending the authToken via `POST.envelope` isn't working. It should be.)

The authentication-related operations are described in this section
(ordered alphabetically by operation name).

The JSON API ties in to/piggybacks on fossil's existing cookie-based
login mechanism, but we must also keep in mind that not all JSON-using
clients support cookies. Cookie-capable clients can rely on cookies for
authentication, whereas non-cookie-aware clients will need to keep track
of the so-called "auth token" which is created via a login request, and
pass it in with each request (either as a GET parameter or a property of
the top-level POST request envelope) to prove to fossil that they are
authorized to access the requested resources. For most intents and
purposes, the "auth token" and the "login cookie" are the same thing (or
serve the same purpose), and the auth token is in fact just the value
part of the login cookie (which has a project-specific key).

Note that fossil has two conventional user names which can show up in
various response but do not refer to specific people: nobody and
anonymous. The nobody user is anyone who is not logged in. The anonymous
user is logged in but has no persistent user data (no associated user
name, email address, or similar). Normally the guest (nobody) user has
more access restrictions. The distinction between the two is largely
historical - it is a mechanism to keep bots from following the
multitudes of links generated by the HTML interface (especially the ZIP
files), while allowing interested users to do so by logging in as the
anonymous user (which bots have (or *had*, at the time) a harder time
doing because the password is randomly generated and protected from
brute-force attacks by hashing). In the JSON API, the distinction
between anonymous and nobody is not expected to be as prominent as it is
in the HTML interface because the reasons for the distinction don't
apply in *quite* the same ways to the JSON interface. It is possible,
however, that a given repo locks out guest access to, e.g. the wiki or
tickets, while still allowing anonymous (logged in) access.

<a id="capabilities"></a>
# Capabilities (Access Rights)

The "cap" request returns information about the so-called "capabilities"
(access rights) of the currently logged in user. This command is
basically the same as the "whoami" command, but returns capabilities in
a more exanded form (same data, different representation) and does not
include the authToken in the response.

TODO: consider combining this and [whoami](#whoami) into a single
whoami response.  We don't need both. We also don't really need the
permissionFlags member - the same info is already \[in a more cryptic form\]
in the capabilities string.

**Status:** implemented 201109xx.

**Required privileges:** none

**Request:** `/json/cap`

In CLI mode, permissions are not used/honored, and this command will
report that the caller has all permissions (which he effectively does).

**Response payload example:**

```json
{
"userName":"json-demo",
"capabilities":"hgjorxz", /* raw fossil permissions list */
"permissionFlags":{ /* Same info in a somewhat friendlier form */
 "setup": false,
 "admin": false,
 "delete": false,
 "password": false,
 "query": false,
 "checkin": false,
 "checkout": true,
 "history": true,
 "clone": false,
 "readWiki": true,
 "createWiki": false,
 "appendWiki": false,
 "editWiki": false,
 "readTicket": true,
 "createTicket": false,
 "appendTicket": false,
 "editTicket": false,
 "attachFile": false,
 "createTicketReport": false,
 "readPrivate": false,
 "zip": true,
 "xferPrivate": false
 }
}
```

**FIXME:** several new permissions have been added to fossil since
this API was implemented.


<a id="login"></a>
# Login

**Status:** implemented 20110915 (anonymous login 20110918)

**Required privileges:** none

**Request:** (see below for Anonymous user special case)

- `/json/login?name=...&password=...`
- `/json/login?n=...&p=...` (for symmetry with existing login mechanism)

Or `POST.payload`: `{ "name": ..., "password": ...}`

(POST is highly preferred because it keeps the password out of web
server logs!)

**Response payload example:** (structure changed 20111001)

```json
{
"authToken":"...",
"name":"json-demo",
"capabilities":"hgjorxz",
"loginCookieName": "fossil-XXXXX" /*project-specific cookie name*/
/* TODO: add authTokenExpiry timestamp (cookie expiry time) */
}
```

We "should" be able to inherit fossil's `REMOTE_USER` handling without
any special support, but that is untested so far. (If you happen to test
this, please update this doc with (or otherwise report) your results!)

The response *also* sets the conventional fossil login cookie (for
clients which can make use of cookies), using fossil's existing
mechanism for this.

Further requests which require authentication must include the
`authToken` (from the returned payload value) in the request (or it must
be available via fossil's standard cookie) or access may (depending on
the request) be denied. The `authToken` may optionally be set in the
request envelope or as a GET parameter, and it *must* be given if the
request requires restricted access to a resource. e.g. if reading
tickets is disabled for the guest user then all non-guest users must
send authentication info in their requests in order to be able to fetch
ticket info.

Cookie-aware clients should send the login-generated cookie with each
request, in which case they do not need explicitly include the
`authToken` in the JSON envelope/GET arguments. If submitted, the
`authToken` is used, otherwise the cookie, if set, is used. Note that
fossil uses a project-dependent cookie name in order to help thwart
attacks, so there is no simple mapping of cookie *name* to auth
token. That said, the cookie's *value* is also the auth token's value.

> Special case: when accessing fossil over a local server instance
which was started with the `--localauth` flag, the `authToken` is ignored
(neither validated nor used for any form of authentication).


<a id="login-anonymous"></a>
## Anonymous User Logins

The Anonymous user requires special handling because he has a random
password.

First fetch the password and the so-called "captcha seed" via this
request:

`/json/anonymousPassword`

It will return a payload in the form:

```json
{
"seed": a_32_bit_unsigned_integer,
"password": "1234abcd" /*hexadecimal STRING*/
}
```

The "seed" and "password" values of the response payload must be set as
the "anonymousSeed" and "password" fields (respectively) of the
subsequent login request. The login request is identical to
non-anonymous login except that extra "anonymousSeed" property is
required.

The password value *may* be time-limited, and *may* eventually become
invalidated due to old age. This is unspecified.

***Potential***** (low-probability) bug regarding the seed value:** from
what i hear, some unusual JSON platforms don't support full 32-bit
precision. If absolutely necessary we could chop off a bit or two from
the seed value (*if* it ever becomes a problem and if DRH blesses it).
Or we could just make it a double.


<a id="logout"></a>
# Logout

**Status:** implemented 20110916

**Required privileges:** none, but must be logged in

**Request:**

  - `/json/logout?authToken=...token fetched by /login`

Or: set the `authToken` property of the POST envelope (as opposed to the
`POST.payload`)

Or: fossil's normal cookie mechanism is the fallback for the auth token.

**Response payload:** The same as the "whoami" response, containing the
info for the "nobody" user.

This request requires the authentication token, and subsequent logouts
without an intervening login will fail with the "auth token not
provided" error. In effect this request removes the login entry from the
user account, making the token invalid for future requests. In HTTP
mode, on success fossil's login cookie is unset by this call.


<a id="whoami"></a>
# Whoami

This request fetches the current user's login name, capabilities, and
auth token. This can be used to check whether a login is active when the
client has not explicitly logged in (e.g. was logged in automatically
via a pre-existing cookie).

**Status:** implemented 20110922

**Required privileges:** none

**Request:** `/json/whoami`

**Response payload example:**

```json
{
"name": "nobody",
"capabilities": "o",
"authToken": "fossil auth token (only for logged-in users)"
}
```

The reason authToken is included in the response is because it gives
client-side JavaScript code a way of fetching/checking for the auth
token at app startup. The token is normally sent as a cookie but parsing
the cookies in the browser is tedious, and fossil has a
project-dependent cookie name (which complicates parsing a bit). If
client code digs the cookie out of the browser, the app still wouldn't
know if the token is still valid, whereas whoami won't (or shouldn't!)
return an expired auth token. If the request does not include
authentication info (via the cookie, GET param, or request envelope)
then the response will not contain the authToken property and the user's
name will be "nobody".
Added www/json-api/api-branch.md.












































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# JSON API: /branch
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Branch List](#list)
* [Create Branch](#create)

---

<a id="list"></a>
# Branch List

**Status:** implemented, at least in draft form, on 20110921.

**Required privileges:** "o"

**Request:** `/json/branch/list`

**Response payload example:**

```json
{
"range":"closed",
"current":"json", /* only when there is a local opened checkout */
"branches":[
  "artifact_description",
  "bch",
  "ben-changes-report",
  "ben-safe-make",
  "ben-security",
  "ben-testing",

]
}
```

*Potential* TODO: add "tip" property which names the most recently
modified branch? (How to get this?)

HTTP GET/`POST.payload` options:

-   `range`: a string in the set ("open", "closed", "all"),
    case-sensitive, but only the first letter is actually evaluated.
    Default="open". Only branches with this state are returned.

CLI mode options (same semantics as HTTP equivalents), must come last on
the CLI:

-   `-r|--range all|closed|open`
-   `-a` (equivalent to `-r all`)
-   `-c` (equivalent to `-r closed`). Only one of `-a`/`-c` may be specified,
    and if both are specified then which one takes precedence is
    unspecified.


<a id="create"></a>
# Create Branch

**Status:** implemented 20111002

**Required privileges:** "w"

**Request:** `/json/branch/create`

**Request options:**

-   `name=string` (REQUIRED) Name of new branch
-   `basis=string` (default=trunk) Name of parent branch to branch from.
-   `bgColor=string` (default=something ugly) In `#RRGGBB` form. (FIXME:
    change the default to use fossil's random bgcolor technique.)
-   `private=bool` (default=false) Determines whether the branch is
    private or not.

**Response payload example:**

```json
{
"name":"my-branch",
"basis":"my-other-branch",
"uuid":"de8115db4ce388ed8d0af666ae7d90e1410be4ca",
"isPrivate":true,
"bgColor":"#ff0000"
}
```

Added www/json-api/api-checkout.md.


























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# JSON API: /status
([&#x2b11;JSON API Index](index.md))

# Status of Local Checkout

**Status:** implemented 20130223

**Required permissions:** n/a (local access only)

**Request:** `/json/status`

This command requires a local checkout and is analog to the "fossil
status" command.

**Request Options:** currently none.

Payload example:

```json
{
"repository":"/home/stephan/cvs/fossil/fossil.fsl",
"localRoot":"/home/stephan/cvs/fossil/fossil/",
"checkout":{
  "uuid":"b38bb4f9bd27d0347b62ecfac63c4b8f57b5c93b",
  "tags":["trunk"],
  "datetime":"2013-02-22 17:34:19 UTC",
  "timestamp":1361554459
 },
/* "parent" info is currently missing. */
"files":[
  {"name":"src/checkin.c", "status":"edited"}
  ...],
"errorCount":0 /* see notes below */
}
```

Notes:

-   The `checkout.tags` property follows the framework-wide convention
    that the first tag in the list is the primary branch and any others
    are secondary.
-   `errorCount` is +1 for each missing file. Conflicts are not treated as
    errors because the CLI 'status' command does not treat them as such.
-   TODO: Info for the parent version is currently missing.
-   TODO: "merged with" info for the checkout is currently missing.
Added www/json-api/api-config.md.








































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# JSON API: /config
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Get Config](#get)
* [Set Config](#set)

---

<a id="get"></a>
# Fetch Config

**Status:** Implemented 20120217

**Required permissions:** "s"

**Request:** `/json/config/get/Area[/Area2/...AreaN]`

Where "Area" can be any combination of: *skin*, *ticket*, *project*,
*all*, or *skin-backup* (which is not included in "all" by default).

**Response payload example:**

```json
{
"ignore-glob":"*~",
"project-description":"For testing Fossil's JSON API.",
"project-name":"fossil-json-tests"
}
```

<a id="set"></a>
# Set/Modify Config

Not implemented.
Added www/json-api/api-diff.md.
























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# JSON API: /diff
([&#x2b11;JSON API Index](index.md))

# Diffs

**Status:** implemented 20111007

**Required permissions:** "o"

**Request:** `/json/diff[/version1[/version2]]`

**Request options:**

-   `v1=string` Is the "from" version. It may optionally be the first
    positional parameter/path element after the command name.
-   `v2=string` Is the "to" version. It may optionally be the first
    positional parameter/path element after the v1 part.
-   `context=integer` (default=unspecified) Defines the number of context
    lines to display in the diff.\  
    CLI: `--context|-c`
-   `sbs=bool` (default=false) Generates "side-by-side" diffs, but their
    utility in JSON mode is questionable.
-   `html=bool` (default=false) causes the output to be marked up with
    HTML in the same manner as it is in the HTML interface.

**Response payload example:**

```json
{
"from":"7a83a5cbd0424cefa2cdc001de60153aede530f5",
"to":"96920e7c04746c55ceed6e24fc82879886cb8197",
"diff":"@@ -1,7 +1,7 @@\\n-C factored\\\\sout..."
}
```

TODOs:

-   Unlike the standard diff command, which apparently requires commit
    UUID, this one diffs individual file versions. If a commit UUID is
    provided, a diff of the manifests is returned. (That should be
    considered a bug - we should return a combined diff in that case.)
-   If UUIDs from two different types of artifacts are given, results
    are unspecified. Garbage in, garbage out, and all that.
-   For file diffs, add the file name(s) to the response payload.
Added www/json-api/api-dir.md.










































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# JSON API: /dir
([&#x2b11;JSON API Index](index.md))

# Directory Listing

**Status:** implemented 20120316

**Required privileges:** "o". Was "h" prior to 20120720, but the HTML
version of /dir changed permissions and this API was modified to match
it.

**Request:** `/json/dir`

Options:

-   `checkin=commit` (use "tip" for the latest). If checkin is not set
    then all files from all versions of the tree are returned (but only
    once per file - not with complete version info for each file in all
    branches).\  
    CLI: `--checkin|-ci CHECKIN`
-   `name=subdirectory` name. To fetch the root directory, don't pass this
    option, or use an empty value or "/".\  
    CLI: use `--name|-n NAME` or pass it as the first argument after
    the `dir` subcommand.

**Response payload example:**

```json
{
 "name":"/", /* dir name */
 "uuid":"ac6366218035ed62254c8d458f30801273e5d4fc",
 "checkin":"tip",
 "entries":[{
  "name": "ajax", /* file name/dir name fragment */
  "isDir": true, /* only set for directories */
  /* The following properties are ONLY set if
   the 'checkin' parameter is provided.
  */
  "uuid": "..." /*only for files, not dirs*/,
  "size": number,
  "timestamp": number
 },...]
}
```

The checkin property is only set if the request includes it. The
entry-specific uuid and size properties (e.g. `entries[0].uuid`) are
only set if the checkin request property is set and they refer to the
latest version of that file for the given checkin. The `isDir` property is
only set on directory entries.

This command does not recurse into subdirectories, though it "should be"
simple enough to add the option to do so.
Added www/json-api/api-finfo.md.










































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# JSON API: /finfo
([&#x2b11;JSON API Index](index.md))

# File Information

**Status:** implemented 2012-something, but output structure is likely
to change.

**Required privileges:** "o"

**Request:** `/json/finfo?name=path/to/file`

Options:

-   `name=string`. Required. Use the absolute name of the file, including
    any directory parts, and without a leading slash. e.g.
    `"path/to/my.c"`.\  
    CLI mode: `--name` or positional argument.
-   `checkin=string`. Only return info related to this specific checkin,
    as opposed to listing all checkins. If set, neither "before" nor
    "after" have any effect.\  
    CLI mode: `--checkin|-ci`
-   `before=DATETIME` only lists checkins from on or before this time.\  
    CLI mode: `--before|-b`
-   `after=DATETIME` only lists checkins from on or before this time.
    Using this option swaps the sort order, to provide reasonable
    behaviour in conjunction with the limit option.\  
    Only one of "before" and "after" may be specified, and if both are
    specified then which one takes precedence is unspecified.\  
    CLI mode: `--after|-a`
-   `limit=integer` limits the output to (at most) the given number of
    associated checkins.\  
    CLI mode: `--limit|-n`

**Response payload example (very likely to change!):**

```json
{
"name":"ajax/i-test/rhino-shell.js",
"checkins":[{
  "checkin":"6b7ddfefbfb871f793378d8f276fe829106ca49b",
  "uuid":"2b735676d55e3d06d670ffbc643e5d3f748b95ea",
  "timestamp":1329514170,
  "user":"viriketo",
  "comment":"<...snip...>",
  "size":6293,
  "state":"added|modified|removed"
  },…]
}
```

**FIXME:** there is a semantic discrepancy between `/json/artifact`'s
`payload.checkins[N].uuid` and this command's.
Added www/json-api/api-misc.md.
























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# JSON API: Misc. APIs
([&#x2b11;JSON API Index](index.md))

Some operations simply don't fit into a specific category (well, none
except "misc")...

Jump to:

* [Global State ("g")](#g)
* [Rebuild Repository](#rebuild)
* [Result Code Descriptions](#result-codes)

---

<a id="g"></a>
# Global State ("g")

Fossil's internal state is maintained in a global object called "g". And
thus this command is named "g"...

**Status:** implemented 20111009

**Required permissions:** "a" or "s"

**Request:** `/json/g`

**Response payload example:** this is a debugging-only request, and has
no stable response payload structure. The result object contains all
kinds of details gleaned from the fossil environment.

Easter egg: this output can be added to ANY response by passing the
`debugFossilG` boolean in the POST envelope or GET parameters, or as the
`--json-debug-g` flag in CLI mode. This requires admin or setup
privileges, though, and it is silently ignored for other users.


<a id="rebuild"></a>
# Rebuild Repository

This request does the same as the "fossil rebuild" command, rebuilding
the repo-internal structure. This is often required after upgrading the
fossil binary on a system. There "are very probably" cases where calling
this over HTTP will not work (e.g. if the user table has changed enough
that the access rights cannot be validated without a rebuild, i.e. a
chicken/egg scenario). Another consideration is that this request can
take a long time to run - rebuilding the fossil repo on my laptop takes
about 21 seconds, which is likely longer than the timeout set on an XHR
request, meaning that the rebuild transaction will fail. It can safely
be run in CLI mode, where timeouts are not normally a concern. As a
preliminary benchmark: rebuilding the fossil repo (as of late 2011)
takes just over 21 seconds on my 32-bit 1.6GHz netbook. That said, most
repos are much smaller and rebuild in under a few seconds.

**Status:** implemented 20110929

**Required privileges:** "a"

**Request:** `/json/rebuild`

Requires admin access rights.

**Response payload:** none (response envelope `resultCode` reports failure).
Potential TODO: return the amount of time it took to rebuild.


<a id="result-codes"></a>
# Result Code Descriptions

This request returns the full list of result codes documented for
Fossil's JSON API. Each result code is returned as an object containing
metadata about the result code.

**Status:** implemented 20111006

**Required permissions:** none

**Request:** `/json/resultCodes`

**Response payload example:**

```json
[{
  "resultCode":"FOSSIL-1000",
  "cSymbol":"FSL_JSON_E_GENERIC",
  "number":1000,
  "description":"Generic error"
 },
 … many more objects with the same structure …
]
```


Added www/json-api/api-query.md.










































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# JSON API: /query
([&#x2b11;JSON API Index](index.md))

# SQL Query

**Status:** implemented 20111008

**Required privileges:** "a" or "s"

**Request:** `/json/query`

Potential FIXME: restrict this to queries which return results, as opposed
to those which may modify data.

Options:

-   `sql=string` The SQL code to run. It is expected that it be a SELECT
    statement, but that is not enforced. This parameter may be set as a
    POST.payload property, as the POST.payload itself, GET, or as a
    positional parameter coming after the command name (CLI and HTTP
    modes, though the escaping would be unsightly in HTTP mode).
-   `format=string` (default="o"). "o" specifies that each result row
    should be in the form of key/value pairs (o=object). "a" means each
    row should be an array of values.

**Example request:**

POST to: `/json/query`

```json
{
"authToken": "...",
"payload": {
  "sql": "SELECT * FROM reportfmt",
  "format": "o"
  }
}
```

**Response payload example:** (assuming the above example)


```
{
"columns":[
  "rn",
  "owner",
  "title",
  "mtime",
  "cols",
  "sqlcode"
 ],
  "rows":[
   {
    "rn":1,
    "owner":"drh",
    "title":"All Tickets",
    "mtime":1303870798,
   },

  ]
}
```

The column names are provided in a separate field is because their order
is guaranteed to match the order of the query columns, whereas object
key/value pairs might get reordered (typically sorted by key) when
travelling through different JSON implementations. In this manner,
clients can e.g. be sure to render the columns in the proper
(query-specified) order.

When in "array" mode the "rows" results will be an array of arrays. For
example, the above "rows" property would instead look like:

`[ [1, "drh", "All Tickets", 1303870798, … ], … ]`

Note the column *names* are never *guaranteed* to be exactly as they
appear in the SQL *unless* they are qualified with an AS, e.g. `SELECT
foo AS foo...`. When generating reports which need fixed column names, it
is highly recommended to use an AS qualifier for every column, even if
they use the same name as the column. This is the only way to guaranty
that the result column names will be stable. (FYI: that behaviour comes
from sqlite3, not the JSON bits, and this behaviour *has* been known to
change between sqlite3 versions (so this is not just an idle threat of
*potential* future incompatibility).)
Added www/json-api/api-stat.md.






















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# JSON API: /stat
([&#x2b11;JSON API Index](index.md))

# Repository Stats

**Status:** implemented

**Required privileges:** "o"

**Request:** `/json/stat`

**Response payload example:** (fields marked with `*` are omitted in
"brief" mode)

```json
{
"projectName":"Fossil",
"projectDescription":"Fossil SCM", /* added 20120217 */
"repositorySize":24464384,
* "blobCount":13612,
* "deltaCount":9348,
* "uncompressedArtifactSize":589205834,
* "averageArtifactSize":43292,
* "maxArtifactSize":4620758,
* "compressionRatio":"24:1",
* "checkinCount":3150,
* "fileCount":456,
* "wikiPageCount":23,
* "ticketCount":940,
"ageDays":1512,
"ageYears":4.139744,
"projectCode":"25d3a4b83202c0d616a5ed17334f180dac4434dc",
"compiler":"gcc-4.1.2 20080704 (Red Hat 4.1.2-50)",
"sqlite":{
  "version":"2011-09-04 01:27:00 [6b657ae750] (3.7.8)",
  "pageCount":23891,
  "pageSize":1024,
  "freeList":2705,
  "encoding":"UTF-8",
  "journalMode":"delete"
}
}
```

**Options:**

-   "Full detail" mode:\  
    **HTTP/payload parameter:** full=bool\  
    **CLI MODE:** -f|--full with no value.\  
    If true then all properties are included, else certain properties
    are omitted from the payload (because they take a relatively long
    time to calculate).\
    **TODO:** rename this to verbose, for consistency.\  
    **Default=false**. *This is in contrast to the HTML interface*,
    which defaults to full detail mode. Testing shows stat to have a
    relatively high per-call cost/run time, so it defaults
    to "brief" mode by default. Full-detail mode can, on slow hardware,
    take half a minute to respond, whereas non-full mode takes well
    under one second.
Added www/json-api/api-tag.md.








































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# JSON API: /tag
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Add](#add)
* [Cancel](#cancel)
* [Find](#find)
* [List](#list)

---

<a id="add"></a>
# Add Tag

**Status:** implemented 20111006

**Required permissions:** "i"

**Request:** `/json/tag/add[/name[/checkin[/value]]]`

**Request options:**

-   `name=string` The tag name.
-   `checkin=string` The checkin to tag. May be a symbolic branch name.
-   raw=bool (=false) If true, then the name is set as it is provided by
    the client, else it gets "sym-" prefixed to it. Do not use this
    unless you really know what you're doing.
-   `value=string` (=null) An optional value. While tags *may* have values
    in fossil, it is unusual for them to have a value. (This probably
    has some interesting uses in custom UIs.)
-   `propagate=bool` (=false) Sets the tag to propagate to all descendants
    of the given checkin.

In CLI modes, the name, checkin, and value parameters may optionally be
supplied as positional parameters (in that order, after the command
name). In HTTP mode they may optionally be the 4th-6th path elements or
specified via GET/`POST.envelope` parameters.

**Response payload example:**

```json
{
"name":"my-tag",
"value":"abc",
"propagate":true,
"raw":false,
"appliedTo":"626ab2f3743543122cc11bc082a0603d2b5b2b1b"
}
```

The appliedTo property is the UUID of the checkin to which the tag was
applied. This is the "resolved" version of the checkin name provided by
the client.

<a id="cancel"></a>
# Cancel Tag

**Status:** implemented 20111006

**Required permissions:** "i"

**Request:** `/json/tag/cancel[/name[/checkin]]`

**Request options:**

-   `name=string` The tag name. May optionally be provided as the 4th path
    element.
-   `checkin=string` The checkin to untag. May be a symbolic branch name.
    May optionally be provided as the 5th path element.

In CLI modes, the name and checkin parameters may optionally be supplied
as positional parameters (in that order, after the command name) or
using the `-name NAME` and `-checkin NAME` options. In HTTP mode they may
optionally be the 4th and 5th path elements.

**Response payload:** none (resultCode indicates failure)


<a id="find"></a>
# Find Tag

Fetches information about artifacts having a particular tag.

Achtung: the output of this response is based on the HTML-mode
implementation, but it's not yet certain that it's exactly what we want
for JSON mode. The request options and response format may change.

**Status:** implemented 20111006

**Required permissions:** "o"

**Request:** `/json/tag/find[/tagName]`

The response format differs somewhat depending on the options:

-   `name=string` The tag name to search for. Can optionally be the 3rd
    path element.
-   `limit=int` (defalt=0) Limits the number of results (0=no limit).
    Since they are ordered from oldest to newest, the newest N results
    will be returned.
-   `type=string` (default=`*`) Searches only for the given type of
    artifact (using fossil's conventional type naming: ci, e, t, w.
-   `raw=bool` (=false) If enabled, the response is an array of UUID
    strings, else it is an array of higher-level objects. If this is
    true, the "name" property is interpretted as-is. If it is false, the
    name is automatically prepended with "sym-" (meaning a branch).
    (FIXME: the current semantics are confusing and hard to remember.
    Re-do them.)

**Response payload example, in RAW mode: (expect this format to change
at some point!)**

```json
{
"name":"sym-trunk"
"raw":true,
"type":"*",
"limit":2,
"artifacts":[
  "a28c83647dfa805f05f3204a7e146eb1f0d90505",
  "dbda8d6ce9ddf01a16f6c81db2883f546298efb7"
 ]
}
```

Very likely todo: return more information with that (at least the
artifact type and timestamp). Once the `/json/artifact` family of bits is
finished we could use that to return artifact-type-dependent values
here.

**Response payload example, in non-raw mode:**

```
{
"name":"trunk",
"raw":false,
"type":"*",
"limit":1,
"artifacts":[{
  "uuid":"4b0f813b8c59ac8f7fbbe33c0a369acc65407841",
  "timestamp":1317833899,
  "comment":"fixed [fc825dcf52]",
  "user":"ron",
  "eventType":"checkin"
 }]
}
```

<a id="list"></a>
# List Tags

**Status:** implemented 20111006

**Required permissions:** "o"

**Request:** `/json/tag/list[/checkinName]`

Potential fixme: we probably have too many different response formats
here. We should probably break this into multiple subcommands.

The response format differs somewhat depending on the options:

-   `checkin=string` Lists the tags only for the given CHECKIN (can be a
    branch name). If set, includeTickets is ignored (meaningless in this
    combination). This option can be set as either a GET/`POST.payload`
    option, as the last element of the request path, e.g.
    `/json/tag/list/MYBRANCH` *or* with `POST.payload` set to a string
    value.
-   `raw=bool` (default=false) uses "raw" tag names
-   `includeTickets=bool` (default=false) Determines whether `tkt-` tags
    are included. There is one of these for each ticket, so there can be
    many of them (over 900 in the main fossil repo as of this writing).

**Response format when raw=false and no checkin is specified:**

```json
{
"raw":false,
"includeTickets":false,
"tags":[
  "bgcolor",
  "branch",
  "closed",
  …all tag names...
 ]
}
```

Enabling the `raw` option will leave the internal `sym-` prefix on tags
which have them but will not change the structure. If `includeTickets` is
true then `tkt-` entries (possibly very many!) will be included in the
output, else they are elided.

**General notes:**

The `tags` property will be null if there are no tags, every non-empty
repo has at least one tag (for the trunk branch).

**Response format when raw=false and checkin is specified:**

```json
{
"raw":false,
"tags":{
  "json":null,
  "json-multitag-test":null
 }
}
```

The `null`s there are the tag values (most tags don't have values).

If `raw=true` then the tags property changes slightly:

```json
{
"raw":true,
"tags":{
  "branch":"json",
  "sym-json":null,
  "sym-json-multitag-test":null
 }
}
```

TODO?: change the tag values to objects in the form
`{value:..., tipUuid:string, propagating:bool}`.
Added www/json-api/api-ticket.md.
















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# JSON API: Tickets
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Ticket Reports](#reports)
  * [Fetch a Report](#report-get)
  * [List Reports](#report-list)
  * [Run a Report](#report-run)


---

# Tickets

This API is incomplete. It is missing at least the following features:

-   Content for a given ticket ID
-   History for a given ticket ID?
-   An option to enable/disable the generation of hyperlinks, as links
    won't be useful in most non-browser clients.


<a id="reports"></a>
# Ticket Reports

<a id="report-get"></a>
## Fetch a Report

**Status:** implemented 20111008

**Required privileges:** "t" (the thinking being that only those
permitted to create reports should be able to read their SQL code)

**Request:** `/json/report/get[/REPORT_NUMBER]`

**Request options:**

-   `report=number` The report number to fetch.\  
    CLI: `-report|-r` \  
    (Design note: `--number/-n` was not used because that parameter has a
    different meaning (limit response count) in several commands.) May
    optionally be defined via the 4th GET path element or CLI arg.

**Response payload example:**

```json
{
"report":1,
"owner":"drh",
"title":"All Tickets",
"timestamp":"112443570187200",
"columns":"#ffffff Key:\r\n#f2dcdc Active\r\n...",
"sqlCode":"..."
}
```

<a id="report-list"></a>
## List Reports

**Status:** implemented 20111008

**Required privileges:** "r" or "n"

**Request:** `/json/report/list`

**Response payload example:**

```json
[
 {
  "report":1,
  "title":"All Tickets",
  "owner":"drh"
  },

]
```

<a id="report-run"></a>
## Run a Report

**Status:** implemented 20111008

**Required privileges:** "r" or "n"

**Request:** `/json/report/run[/REPORT_NUMBER]`

Request options:

-   `report|-r=int` Specifies which report to run. May optionally be
    supplied as the 4th CLI arg or URL path element.
-   `format|-f=string` (default="o") Specifies "array" or "object" output
    format.

**Response payload example:**

```json
{
  "report":1,
  "title":"All Tickets",
  "sqlcode": "only set if requester has 't' privileges.",
  "columnNames":[ … list of column names … ],
  "tickets":[
    {
      "bgcolor":"#cfe8bd",
      "#":"fc825dcf52",
      "timestamp":"112443570187200",
      "type":"Code_Defect",
      "status":"Fixed",
      "subsystem":null,
      "title":"\"config pull all\" asks to approve ssl cert"
    },

  ]
}
```

Note that the column names of ticket reports are determined by the
reports themselves, and not C code. That means that we cannot return a
standard set of column names here. Fossil requires certain column naming
conventions for purposes of styling the HTML interface, e.g. the "\#"
column is always the uuid of the record and "bgcolor" (note the
different casing than bgColor used throughout the rest of this API!) has
a specific meaning to the HTML report browser. Fossil also allows the
tickets to be extended with client-specified fields, so we cannot
generically make these results fit into the API-wide naming scheme. Full
details are here:

[](/doc/trunk/www/custom_ticket.wiki)

and:

[](/rptsql?rn=1)

(That one may require non-default permission.)
Added www/json-api/api-timeline.md.










































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# JSON API: /timeline
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Introduction](#intro)
* [Branch Timeline](#branch)
* [Technote (formerly Event) Timeline](#technote)
* [Ticket Timeline](#ticket)
* [Wiki Timeline](#wiki)

---

<a id="intro"></a>
# Introduction

These requests return overview-level information about various types of
changes. The response payload differs for each artifact type, and the
current structures are almost certainly not "final" (e.g. we are still
undecided on how/whether to handle artifact links within commit messages
and whatnot).

By default the entries are returned in chronological order from newest
to oldest, but some options might change that.

FIXME (20120623): we have some inconsistent `type` vs. `eventType` in
the result sets. `type` is the current preferred choice (and it seems
unlikely that `eventType` is actually used in any client code). We
don't actually need either one (but a use for `type` is easily
envisioned), and we may get rid of both.

**Common request options (via CLI, GET or POST.payload):**

-   `limit=integer` limits the number of entries in the response. Default
    is unspecified (but is "quite possibly 20 or so"). A limit value of
    0 disables any limit, fetching all entries (which can take a really
    long time and might overload clients which have very limited
    memory).\  
    CLI mode: `--limit|-n #`
-   `after="YYYY-MM-DD[ HH:mm:ss]"` limits the search to items on or
    after the given date string. Reverses the normal timeline sort
    order. Alias: "a". Only one of "after" or "before" can be used, and
    if both are specified then which one takes precedence is
    unspecified.\  
    CLI mode: `--after|-a "DATE[ TIME]"`
-   `before="YYYY-MM-DD[ HH:mm:ss]"` limits the search to items on or
    before the given date string.\  
    CLI mode: `--before|-b "DATE[ TIME]"
-   TODOs, still to be ported from the HTML-mode timeline:
    -   circa=DATETIME
    -   tag=string
    -   related=tag name
    -   string=search string

<a id="branch"></a>
# Branch Timeline

**Status:** partially implemented but undocumented because the utility
of the current impl is under question. It also doesn't understand most
of the common timeline options.

<a id="checkin"></a>
# Checkin Timeline

**Status:** implemented 201109xx

**Required privileges:** "o"

**Request:** `/json/timeline/checkin`

**Response payload example:**

```json
{
"limit": number, /* if not set, all records are returned */
"timeline":[{
  "uuid":"be700e84336941ef1bcd08d676310b75b9070f43",
  "timestamp":1317094090,
  "comment":"Added /json/timeline/ci showFiles to ajax test page.",
  "user":"stephan",
  "isLeaf":true,
  "bgColor":null, /* not quite sure why this is null? */
  "type":"ci",
  "parents": ["primary parent UUID", "...other parent UUIDs"],
  "tags":["json"],
  "files":[{
    "name":"ajax/index.html",
    "uuid":"9f00773a94cea6191dc3289aa24c0811b6d0d8fe",
    "parent":"50e337c33c27529e08a7037a8679fb84b976ad0b",
    "state":"modified"
   }]
 },...]
}
```

(Achtung: the `parents` property was called `prevUuid` prior to 20120316.)

The `parents` property lists the checkins which were parents of this
commit. The first entry in the array is the "primary parent" - the one
which was not involved in a merge with the child.

**Request options:**

-   `files=bool` toggles the addition of a "files" array property which
    contains objects describing the files changed by the commit,
    including their uuid, previous uuid, and state change type
    (modified, added, or removed).\  
    CLI mode: `--show-files|-f`
-   `tag|branch=string` selects only entries with the given tag or "close
    to" the given branch. Only one of these may be specified and if both
    are specified, which one takes precedence is unspecified. If the
    given tag/branch does not exist, an error response is generated. The
    difference between the two is subtle - tag filters only on the given
    tag (analog to the HTML interface's "r" option) whereas branch can
    also return entries from other branches which were merged into the
    requested branch (analog to the HTML interface's "b" option). If one
    of these is specified, the response payload will contain a "tag"
    *or* "branch" property with the tag/branch name given by the client.

<a id="technote"></a>
# Technote (formerly Event) Timeline

**Status:** implemented 20180803

**Required privileges:** "j"

**Request:**

- `/json/timeline/technote`
- DEPRECATED: `/json/timeline/event` (technotes were formerly called `events`)

**Response payload example:**

```json
{
"limit": number, /* if not set, all records are returned */
"timeline":[{
  "name":"8d18bf27e9f9ff8b9017edd55afc35701407d418",
  "uuid":"b23962c88c123924a77fd663e91af094780d920a",
  "timestamp":1478376113,
  "comment":"Style update due to [8d880f0bb4]",
  "user":"andygoth",
  "eventType":"e"
 },...]
}
```

The `uuid` of each entry can be passed to `/json/artifact` to fetch the raw
event content.

<a id="ticket"></a>
# Ticket Timeline

**Status:** implemented 201109xx

**Required privileges:** "r" or "o"

**Request:** `/json/timeline/ticket`

**Response payload example:**

```json
{
  "limit": number, /* if not set, all records are returned */
  "timeline":[{
    "uuid":"5065a5da060e181da49a618f8ae5dc245215e95b",
    "timestamp":1316511322,
    "user":"stephan",
    "eventType":"t",
    "comment":"Ticket [b64435dba9] &lt;i&gt;How to...&lt;/i&gt;",
    "briefComment":"Ticket [b64435dba9]: 2 changes",
    "ticketUuid":"b64435dba9cceb709bd54fbc5883884d73f93491"
  },...]
}
```

**Notice that there are two UUIDs for tickets** - `uuid` is the change
UUID and `ticketUuid` is the actual ticket. This is an unfortunate
discrepancy vis-a-vis the other timeline entries, which only have one
uuid. We may want to swap uuid to mean the ticket uuid and change uuid
to commitUuid.

<a id="wiki"></a>
# Wiki Timeline

**Status:** implemented 201109xx

**Required privileges:** "j" or "o"

**Requests:**

-   `/json/timeline/wiki`
-   `/json/wiki/timeline` (alias)

**Response payload example:**

```json
{
"limit": number, /* if not set, all records are returned */
"timeline":[{
  "uuid":"4b2026f06eb48eaf187209fcb05ba5438c3b0ef0",
  "timestamp":1331351121,
  "comment":"Changes to wiki page [Page3]",
  "user":"stephan",
  "eventType":"w"
 },...]
}
```

The `uuid` of each entry can be passed to `/json/artifact` or
`/json/wiki/get?uuid=...` to fetch the raw page and the uuid of the
parent version.

Added www/json-api/api-user.md.




























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# JSON API: /user
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Get User Info](#get)
* [List Users](#list)
* [Save User](#save)

---

<a id="get"></a>
# Get User Info

**Status:** implemented 20110927.

**Required privileges:** "a" or "s"

**Request:**

-   POST `/json/user/get`\  
    with `POST.payload.name=USERNAME`
-   `/json/user/get?name=USERNAME`

**Response payload example:**

```json
{
  "uid":1,
  "name":"stephan",
  "capabilities":"abcdefhgijkmnopqrstuvwxz",
  "info":"https://wanderinghorse.net/home/stephan/",
  "timestamp":1316122562
}
```

(What does that timestamp field represent, anyway?)

<a id="list"></a>
# List Users

**Status:** implemented 20110927.

**Required privileges:** "a" or "s"

**Request:** `/json/user/list`

**Response payload example:**

```json
[
 {
  "uid":1,
  "name":"stephan",
  "capabilities":"abcdefhgijkmnoprstuvwxz",
  "info":"",
  "timestamp":1316122562
 },
 ... more users...
]
```


<a id="save"></a>
# Save User

Only admin/setup users may modify accounts other than their own.

**Status:** implemented 20111021 *but* it is missing "login group"
support, so changes do not yet propagate to other repos within a group.

**Required privileges:** 'p' or 'a' or 's', depending on the context.

**Request:** `/json/user/save`

All request options must come from the `POST.payload` and/or GET/CLI
parameters (exception: "name" must come from POST.payload or CLI).
GET/CLI parameters take precedence over those in `POST.payload`, the
intention being to use an input file as a template and overriding the
template's defaults via the CLI. The options include:

-   `name=string` Specifies the user name to change. When changing a
    user's name, the current uid and the new name must be specified.\  
    **Achtung:** due to fossil-internal ambiguity in the handling of the
    "name" parameter, this parameter must come from the `POST.payload`
    data or it will not be recognized. In CLI mode it may be specified
    with the `--name` flag.
-   `uid=int` Specifies the uid to change. At least one of uid or name are
    required. A uid of -1 means to create a new user, in which case the
    name must be provided.
-   `password=string` Optionally changes the user's password. When
    renaming existing or creating new users, be sure to always provide a
    new password because any old password hash is invalidated by the
    name change.
-   `info=string` Optionally changes the user's info field.
-   `capabilities=string` Optionally changes the user's capabilities
    field.
-   `forceLogout=bool` (=false, or true when renaming) Optionally clears
    any current login info for the current user, which will invalidate
    any active session. Requires 'a' or 's' privileges. Intended to be
    used when disabling a user account, to ensure that any open session
    is invalidated. When a user is renamed this option is implied (and
    cannot be disabled) because renaming invalidates any currently
    stored auth token (because the old name is part of the hash
    equation).

Fields which are not provided in the request will not be modified.
Non-admin/setup users cannot edit other users and may only change their
own data if they have the 'p' (password) privilege.

As of 20120217, users who do not have the setup privilege may neither
change the setup privilege for any user nor edit another user who has
that privilege. That is, only users with setup access may propagate or
remove setup status and accounts with the setup privilege may only be
edited by themselves and other setup users.

**Response payload:** Same as user/get, using the new/saved state of the
modified user.

Example usage from the command line:

```console
$ fossil json user save --name drh --password sqlite3 \
 --capabilities "as" --info "DRH"
$ fossil json user save --uid 1 --name richard \
 --password fossil \
 --info "Previously known as drh"
```

**Warnings:**

-   When creating a new user or renaming a user, if no (new) password is
    specified in the save request then the user will not be able to log
    in because the previous password (for existing users) is hashed
    against the old name.
-   Renaming a user invalidates any active login token because his old
    name is a part of the hash. i.e. the user must log back in with the
    new name after being renamed.

**TODOs:**

-   Login group support.
Added www/json-api/api-version.md.
































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# JSON API: /version
([&#x2b11;JSON API Index](index.md))

# Version (a.k.a. HAI)

**Status:** implemented

**Required privileges:** none

**Requests:**

-   `/json/version`
-   `/json/HAI` (alias borrowed from LOLCATZ jargon)

**Response payload example:**

```json
{
"manifestUuid":"20ff808f9809541d2eca6c49a17d5cbd16e1b93f",
"manifestVersion":"[20ff808f98]",
"manifestDate":"2011-09-09 16:49:23",
"manifestYear":"2011",
"releaseVersion":"1.19",
"releaseVersionNumber":119,
"jsonApiVersion": "YYYYMMDD" // added 20120409
}
```

Those particular payload fields were chosen only because they're defined
in `VERSION.h`. We may want to add other information, but nothing comes to
mind at this time.

Added www/json-api/api-wiki.md.
































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# JSON API: /wiki
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Page List](#list)
* [Fetch a Page](#get)
* [Create or Save Page](#create-save)
* [Wiki Diffs](#diffs)
* [Preview](#preview)
* [Notes and TODOs](#todo)

---

<a id="list"></a>
# Page List

Returns a list of all pages, not including their content (which can be
arbitrarily large).

**Status:** implemented 201109xx

**Required privileges:** "j" or "o"

**Request:** `/json/wiki/list`

**Options:**

-   `bool verbose` (=false) Changes the results to return much more
    information. Added 20120219.
-   `glob=wildcard` string (default=`*`). If set, only page names
    matching the given wildcard are returned. Added 20120325.\  
    CLI: `--glob|-g STRING`
-   `like=SQL LIKE string` (default=`%`). If set, only page names matching
    the given SQL LIKE string are returned. Note that this match is
    case-INsensitive. If both glob and like are given then only one will
    work and which one takes precedence is unspecified. Added 20120325.\  
    CLI: `--like|-l STRING`
-   `invert=bool` (default=false). If set to a true value, the glob/like
    filter has a reverse meaning (pages *not* matching the wildcard are
    returned). Added 20120329.\  
    CLI: `-i/--invert`

**Response payload: format depends on "verbose" option**

Non-verbose mode:

```json
["PageName1",..."PageNameN"]
```

In verbose mode:

```json
[{
"name":"Apache On Windows XP",
"uuid":"a7e68df71b95d35321b9d9aeec3c8068f991926c",
"user":"jeffrimko",
"timestamp":1310227825,
"size":793 /* in bytes */
},...]
```

The verbose-mode output is the same as the [`/json/wiki/get`](#get) output, but
without the content. The size property of each reflects the *byte*
length of the raw (non-HTMLized) page content.

**Potential TODOs:**

-   Allow specifying (in the request) a list/array of names, as opposed
    to listing all pages. The page count is rarely very high, though, so
    an "overload" is very unlikely. (i have one wiki with about 47 pages
    in it.)

<a id="get"></a>
# Fetch a Page

Fetches a single wiki page, including content and significant metadata.

**Status:** implemented 20110922, but response format may change.

**Required privileges:** "j" or "o"

**Request:**

-   GET: `/json/wiki/get?name=PageName`
-   GET: `/json/wiki/get/PageName`
-   POST: `/json/wiki/get` with page name as `POST.payload` or
    `POST.payload.name`.

**Response payload example:**

```json
{
"name": "Fossil",
"uuid": "...hex string...",
"parent": "uuid of parent (not set for first version of page)",
"user": "anonymous",
"timestamp": 1286143975,
"size": 1906, /* In bytes, not UTF8 characters!
                 Affected by format option! */
"content": "..."
}
```

**FIXME:** it's missing the mimetype (that support was added to fossil
after this was implemented).

If given no page to load, or if asked to get a page which does not
exist, an error response is generated (a usage- or resource-not-found
error, respectively).

**Options (via CLI/GET/`POST.payload`):**

- `name=string`. The page to fetch. The latest version is fetched
unless the uuid paramter is supplied (in which case name is ignored). \  
CLI: `--name|-n string`\  
Optionally, the name may be the 4th positional argument/request path element.
- `uuid=string`. Fetches a specific version. The name parameter is
ignored when this is specified.\  
CLI: `--uid|-u string`
- `format=string ("raw"|"html"|"none")` (default="raw"). Specifies the
format of the "content" payload value.\  
CLI: `--format|-f string` \  
The "none" format means to return no content. In that case the size
refers to the same size as the "raw" format.

**TODOs:**

-   Support passing an array of names in the request (and change
    response to return an array).

<a id="create-save"></a>
# Create or Save Page

**Status:** implemented 20110922.

**Required privileges:** "k" (save) or "f" (create)

**Request:**

-   `/json/wiki/create`
-   `/json/wiki/save`

These work only in HTTP mode, not CLI mode. (FIXME: now that we can
simulate POST from a file, these could be used in CLI mode.)

The semantic differences between save and create are:

-   Save will fail if the page doesn't already exist whereas create will
    fail if it does. The createIfNotExists option (described below) can
    be used to create new pages using the save operation.
-   The content property is optional for the create request, whereas it
    is required to be a string for save requests (but it *may* be an
    empty string). This requirement for save is *almost* arbitrary, and
    is intended to prevent accidental erasing of existing page content
    via API misuse.

**Response payload example:**

The same as for [`/json/wiki/get`](#get) but the page content is not
included in the response (only the metadata).

**Request options** (via GET or `POST.payload` object):

-   `name=string` specifies the page name.
-   `content=string` is the body text.\  
    Content is required for save (unless `createIfNotExists` is true *and*
    the page does not exist), optional for create. It *may* be an empty
    string.
-   Save (not create) supports a `createIfNotExists` boolean option which
    makes it a functional superset of the create/save features. i.e. it
    will create if needed, else it will update. If createIfNotExists is
    false (the default) then save will fail if given a page name which
    does not refer to an existing page.
-   **TODO:** add `commitMessage` string property. The fossil internals
    don't have a way to do this at the moment (they can as of late 2019).
    Since fossil wiki commits have always had the same default commit message, this is not a
    high-priority addition. See:\  
    [](/doc/trunk/www/fileformat.wiki#wikichng)
-   **Potential TODO:** we *could* optionally also support
    multi-page saving using an array of pages in the request payload:\  
    `[… page objects … ]`


<a id="diffs"></a>
# Wiki Diffs

**Status:** implemented 20120304

**Required privileges:** "h"

**Request:**

-   `/json/wiki/diff[/version1_UUID/version2_UUID]`

**Response payload example:**

```json
{
  "v1":"e32ccdcda59e930c77c1e01cebace5d71253f621",
  "v2":"e15992f475760cdf3a9564d8f88cacb659ab4b07",
  "diff":"@@ -1,4 +1,9 @@...<SNIP>..."
}
```

**Options:**

-   `v1=uuid` and `v2=uuid` specify the two versions to diff, and are
    required parameters. They may optionally be specified as the two
    URL/CLI parameters following the "diff" sub-command/path.

This command does not verify that both UUIDs actually refer to the same
page name, but do verify that they refer to wiki content.

Trivia: passing the same UUIDs to the `/json/diff` command will produce
very different results - that one diffs the manifests of the commits.

**TODOs:**

-   Add options for changing the format of the diff, e.g. side-by-side
    and enabling the HTML markup supported by the main fossil HTML GUI.
-   Potentially do a name comparison to verify that the diff is against
    the same page. That said, when "renaming" pages it might be useful
    to diff two different pages.

<a id="preview"></a>
# Preview

**Status:** implemented 20120310

**Required privileges:** "k" (to limit its use to only those who can
edit wiki pages). This limitation is up for debate/reconsideration.

**Request:**

-   `/json/wiki/preview`

This command wiki-processes arbitrary text sent from the client. To help
curb potential abuse, its use is restricted to those with "k" access
rights.

The `POST.payload` property must be a string containing Fossil wiki
markup. The response payload is also a string, but contains the
HTML-processed form of the string. Whether or not "all HTML" is allowed
depends on site-level configuration options, and that changes how the
input is processed.

Note that the links in the generated page are for the HTML interface,
and will not work as-is for arbitrary JSON clients. In order to
integrate the parsed content with JSON-based clients the HTML will
probably need to be post-processed, e.g. using jQuery to fish out the
links and re-map wiki page links to a JSON-capable page handler.

**TODO**: Update this to accept the other two wiki formats (which
didn't exist when this API was implemented): markdown and plain text
(which gets HTML-ized for preview purposes). That requires changing
the payload to an object, perhaps simply submitting the same thing as
`/json/save`. There's no reason we can't support both call forms.


<a id="todo"></a>
# Notes and TODOs

-   When server-parsing the wiki content, the generated
    intra-wiki/intra-site links will only be useful in the context of
    the original fossil UI (or a work-alike), not arbitrary JSON
    client apps.

Potential TODOs:

-   `/wiki/history` analog to the [](/whistory) page.
Added www/json-api/conventions.md.
















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
# JSON API: General Conventions
([&#x2b11;JSON API Index](index.md))

Jump to:

* [JSON Property Naming](#property-names)
* [HTTP GET Requests](#http-get)
* [HTTP POST Requests](#http-post)
    * [POST Request Envelope](#request-envelope)
* [Request Parameter Data Types](#request-param-types)
* [Response Envelope](#response-envelope)
* [HTTP Response Headers](#http-response-header)
* [CLI vs. HTTP Mode](#cli-vs-http)
* [Simulating POSTed data](#simulating-post-data)
* [Indentation/Formatting of JSON Output](#json-indentation)
* [JSONP](#jsonp)
* [API Result Codes](#result-codes)

---

<a id="property-names"></a>
# JSON Property Naming

Since most JSON usage conventionally happens in JavaScript
environments, this API has (without an explicit decision ever having
been made) adopted the ubiquitous JavaScript convention of
`camelCaseWithStartingLower` for naming properties in JSON objects.

<a id="http-get"></a>
# HTTP GET Requests

Many (if not most) requests can be made via simple GET requests, e.g. we
*could* use any of the following patterns for a hypothetical JSON-format
timeline:

- `https://..../timeline/json`
- `/timeline?format=json`
- `/timeline?json=1`
- `/timeline.json`
- `/json/timeline?...options...`

The API settled on the `/json/...` convention, primarily because it
simplifies dispatching and argument-handling logic compared to the
`/[.../]foo.json` approach. Using `/json/...` allows us to unify that
logic for all JSON sub-commands, for both CLI and HTTP modes.

<a id="http-post"></a>
# HTTP Post Requests

Certain requests, mainly things like editing checkin messages and
committing new files entirely, require POST data. This is fundamentally
very simple to do - clients post plain/unencoded JSON using a common
wrapper envelope which contains the request-specific data to submit as
well as some request-independent information (like authentication data).

<a id="request-envelope"></a>
## POST Request Envelope

POST requests are sent to the same URL as their GET counterpart (if any,
else their own path), and are sent as plain-text/unencoded JSON wrapped
in a common request envelope with the following properties:

- `requestId`: Optional arbitrary JSON value, not used by fossil, but
  returned as-is in responses.
- `command`: Provides a secondary mechanism for specifying which JSON
  command should be run. A request path of /json/foo/bar is equivalent
  to a request with path=/json and command=foo/bar. Note that subpaths
  do not work this way. e.g. path=/json/foo, command=bar will not
  work, but path=/json, command=foo/bar will.  This option is
  particularly useful when generating JSON for piping in to CLI mode,
  but it also has some response-dispatching uses on the client side.
- `authToken`: Authentication token. Created by a login
  request. Determines what access rights the user has, and any given
  request may require specific rights. In principle this is required
  by any request which needs non-guest privileges, but cookie-aware
  clients do not manually need to track this (it is managed as a
  cookie by the agent/browser).
    - Note that when accessing fossil over a local server instance
    which was started with the `--localauth` flag, the `authToken`
    will be ignored and need not be sent with any requests. The user
    will automatically be given full privileges, as if they were
    using CLI mode.
- `payload`: Command-specific parameters. Most can optionally come in
  via GET parameters, but those taking complex structures expect them
  to be placed here.
- `indent`: Optionally specifies indentation for the output. 0=no
  indention. 1=a single TAB character for each level of
  indentation. >1 means that many spaces per level. e.g. indent=7
  means to indent 7 spaces per object/array depth level. cson also
  supports other flags for fine-tuning the output spacing, and adding
  them to this interface might be interesting at some
  point. e.g. whether or not to add a newline to the output.  CLI mode
  adds extra indentation by default, whereas CGI/server modes produce
  unindented output by default.
- `jsonp`: Optional String (client function name). Requests which
  include this will be returned with `Content-Type
  application/javascript` and will be wrapped up in a function call
  using the given name. e.g. if `jsonp=foo` then the result would look like:\  
`foo( {...the response envelope...} )`

The API allows most of those (normally all but the payload) to come in
as either GET parameters or properties of the top-level POSTed request
JSON envelope, with GET taking priority over POST. (Reminder to self: we
could potentially also use values from cookies. Fossil currently only
uses 1 cookie (the login token), and i'd prefer to keep it that way.)

POST requests without such an envelope will be rejected, generating a
Fossil/JSON error response (as opposed to an HTTP error response). GET
requests, by definition, never have an envelope.

POSTed client requests *must* send a Content-Type header of either
`application/json` , `application/javascript`, or `text/plain`, or the
JSON-handling code will never see the POST data. The POST handler
optimistically assumes that type `text/plain` "might be JSON", since
`application/json` is a newer convention which many existing clients
do not use (as of the time these docs were written, back in 2011).

## POST Envelope vs. `POST.payload`


When this document refers to POST data, it is referring to top-level
object in JSON-format POSTed input data. When we say `POST.payload` we
refer to the "payload" property of the POST data. While fossil's core
handles *form-urlencoded* POST data, if such data is sent in then
parsing it as JSON cannot succeed, which means that (at worst) the
JSON-mode bits will "not see" any POST data. Data POSTed to the JSON API
must be sent non-form-urlencoded (i.e. as plain text).

Framework-level configuration options are always set via the top-level
POST envelope object or GET parameters. Request-specific options are set
either in `POST.payload` or GET parameters (though the former is required
in some cases). Here is an example which demonstrates the possibly
not-so-obvious difference between the two types of options (framework
vs. request-specific):

```json
{
"requestId":"my request", // standard envelope property (optional)
"command": "timeline/wiki", // also standard
"indent":2, // output indention is a framework-level option
"payload":{ // *anything* in the payload is request-specific
   "limit":1
}
}
```

When a given parameter is set in two places, e.g. GET and POST, or
POST-from-a-file and CLI parameters, which one takes precedence
depends on the concrete command handler (and may be unspecified). Most
will give precedence to CLI and GET parameters, but POSTed values are
technically preferred for non-string data because no additional "type
guessing" or string-to-whatever conversion has to be made (GET/CLI
parameters are *always* strings, even if they look like a number or
boolean).


<a id="request-param-types"></a>
# Request Parameter Data Types

When parameters are sent in the form of GET or CLI arguments, they are
inherently strings. When they come in from JSON they keep their full
type (boolean, number, etc.). All parameters in this API specify what
*type* (or types) they must (or may) be. For strings, there is no
internal conversion/interpretation needed for GET- or CLI-provided
parameters, but for other types we sometimes have to convert strings to
other atomic types. This section describes how those string-to-whatever
conversions behave.

No higher-level constructs, e.g. JSON **arrays** or **objects**, are
accepted in string form. Such parameters must be set in the POST
envelope or payload, as specified by the specific API.

This API does not currently use any **floating-point** parameters, but
does return floating-point results in a couple places.

For **integer** parameters we use a conventional string-to-int algorithm
and assume base 10 (analog to atoi(3)). The API may err on the side of
usability when given technically invalid values. e.g. "123abc" will
likely be interpreted as the integer 123. No APIs currently rely on
integer parameters with more than 32 bits (signedness is call-dependent
but few, if any, use negative values).

**Boolean** parameters are a bit schizophrenic...

In **CLI mode**, boolean flags do not have a value, per se, and thus
require no string-to-bool conversion. e.g. `fossil foo -aBoolOpt
-non-bool-opt value`.

Those which arrive as strings via **GET parameters** treat any of the
following as true: a string starting with a character in the set
`[1-9tT]`. All other string values are considered to be false for this
purpose.

Those which are part of the **POST data** are normally (but not always -
it depends on the exact context) evaluated as the equivalent of
JavaScript booleans. e.g. if we have `POST.envelope.foo="f"`, and evaluate
it as a JSON boolean (as opposed to a string-to-bool conversion), the
result will be true because the underlying JSON API follows JavaScript
semantics for any-type-to-bool conversions. As long as clients always
send "proper" booleans in their POST data, the difference between
GET/CLI-provided booleans should never concern them.

TODO: consider changing the GET-value-to-bool semantics to match the JS
semantics, for consistency (within the JSON API at least, but that might
cause inconsistencies vis-a-vis the HTML interface).

<a id="response-envelope"></a>
# Response Envelope

Every response comes in the form of a HTTP response or (in CLI mode)
JSON sent to stdout. The body of the response is a JSON object following
a common envelope format. The envelope has the following properties:


- `fossil`: Fossil server version string. This property is basically
  "the official response envelope marker" - if it is set, clients can
  "probably safely assume" that the object indeed came from one of the
  Fossil/JSON APIs. This API never creates responses which do not
  contain this property.
- `requestId`: Only set if the request contained it, and then it is
  echoed back to the caller as-is. This can be use to determine
  (client-side) which request a given response is coming in for
  (assuming multiple asynchronous requests are pending). In practice
  this generally isn’t needed because response handling tends to be
  done by closures associated with the original request object (at
  least in JavaScript code). In languages without closures it might
  have some use. It may be any legal JSON value - it need not be
  confined to a string or number.
- `resultCode`: Standardized result code string in the form
  `FOSSIL-####`. Only error responses contain a `resultCode`.
- `resultText`: Possibly a descriptive string, possibly
  empty. Supplements the resultCode, but can also be set on success
  responses (but normally isn't). Clients must not rely on any
  specific values being set here.
- `payload`: Request-specific response payload (data type/structure is
  request-specific).  The payload is never set for error responses,
  only for success responses (and only those which actually have a
  payload - not all do).
- `timestamp`: Response timestamp (GMT Unix Epoch). We use seconds
  precision because i did not know at the time that Fossil actually
  records millisecond precision.
- `payloadVersion`: Not initially needed, but reserved for future use
  in maintaining version compatibility when the format of a given
  response type's payload changes. If needed, the "first version"
  value is assumed to be 0, for semantic [near-]compatibility with the
  undefined value clients see when this property is not set.
- `command`: Normalized form of the command being run. It consists of
  the "command" (non-argument) parts of the request path (or CLI
  positional arguments), excluding the initial "/json/" part. e.g. the
  "command" part of "/json/timeline/checkin?a=b" (CLI: json timeline
  checkin...)  is "timeline/checkin" (both in CLI and HTTP modes).
- `apiVersion`: Not yet used, but reserved for a numeric value which
  represents the JSON API's version (which can be used to determine if
  it has a given feature or not). This will not be implemented until
  it's needed.
- `warnings`: Reserved for future use as a standard place to put
  non-fatal warnings in responses. Will be an array but the warning
  structure/type is not yet specified. Intended primarily as a
  debugging tool, and will "probably not" become part of the public
  client interface.
- `g`: Fossil administrators (those with the "a" or "s" permissions)
  may set the `debugFossilG` boolean request parameter (CLI:
  `--json-debug-g`) to enable this property for any given response. It
  contains a good deal of the server-side internal state at the time
  the response was generated, which is often useful in debuggering
  problems. Trivia: it is called "g" because that's the name of
  fossil's internal global state object.
- `procTimeMs`: For debugging only - generic clients must not rely on
  this property. Contains the number of milliseconds the JSON command
  processor needed to dispatch and process the command. TODO: move the
  timer into the fossil core so that we can generically time its
  responses and include the startup overhead in the time calculation.



<a id="http-response-header"></a>
# HTTP Response Headers

The Content-Type HTTP header of a response will be either
application/json, application/javascript, or text/plain, depending on
whether or not we are in JSONP mode or (failing that) the contents of
the "Accept" header sent in the request. The response type will be
text/plain if it cannot figure out what to do. The response's
Content-Type header *may* contain additional metadata, e.g. it might
look like: application/json; charset=utf-8

Apropos UTF-8: note that JSON is, by definition, Unicode and recommends
UTF-8 encoding (which is what we use). That means if your console cannot
handle UTF-8 then using this API in CLI mode might (depending on the
content) render garbage on your screen.


<a id="cli-vs-http"></a>
# CLI vs. HTTP Mode

CLI (command-line interface) and HTTP modes (CGI and standalone server)
are consolidated in the same implementations and behave essentially
identically, with only minor exceptions.

An HTTP path of `/json/foo` translates to the CLI command `fossil json
foo`. CLI mode takes options in the fossil-convention forms (e.g. `--foo 3`
or `-f 3`) whereas HTTP mode takes them via GET/POST data (e.g. `?foo=1`).
(Note that per long-standing fossil convention CLI parameters taking a
value do not use an equal sign before the value!)

For example:

-   HTTP: `/json/timeline/wiki?after=2011-09-01&limit=3`
-   CLI: `fossil json timeline wiki --after 2011-09-01 --limit 3`

Some commands may only work in one mode or the other (for various
reasons). In CLI mode the user automatically has full setup/admin
access.

In HTTP mode, request-specific options can also be specified in the
`POST.payload` data, and doing so actually has an advantage over
specifying them as URL parameters: posting JSON data retains the full
type information of the values, whereas GET-style parameters are always
strings and must be explicitly type-checked/converted (which may produce
unpredictable results when given invalid input). That said, oftentimes
it is more convenient to pass the options via URL parameters, rather
than generate the request envelope and payload required by POST
requests, and the JSON API makes some extra effort to treat GET-style
parameters type-equivalent to their POST counterparts. If a property
appears in both GET and `POST.payload`, GET-style parameters *typically*
take precedence over `POST.payload` by long-standing convention (=="PHP
does it this way by default").

(That is, however, subject to eventual reversal because of the
stronger type safety provided by POSTed JSON. Philosophically
speaking, though, GET *should* take precedence, in the same way that
CLI-provided options conventionally override app-configuration-level
options.)

One notable functional difference between CLI and HTTP modes is that in
CLI mode error responses *might* be accompanied by a non-0 exit status
(they "should" always be, but there might be cases where that does not
yet happen) whereas in HTTP mode we always try to exit with code 0 to
avoid generating an HTTP 500 ("internal server error"), which could keep
the JSON response from being delivered. The JSON code only intentionally
allows an HTTP 500 when there is a serious internal error like
allocation or assertion failure. HTTP clients are expected to catch
errors by evaluating the response object, not the HTTP result code.

<a id="simulating-post-data"></a>
# Simulating POSTed data

We have a mechanism to feed request data to CLI mode via
files (simulating POSTed data), as demonstrated in this example:

```console
$ cat in.json
{ "command": "timeline/wiki", "indent":2, "payload":{"limit":1}}
$ fossil json --json-input in.json # use filename - for stdin
```

The above is equivalent to:

```console
$ echo '{"indent":2, "payload":{"limit":1}}' \
 | fossil json timeline wiki --json-input -
```

Note that the "command" JSON parameter is only checked when no json
subcommand is provided on the CLI or via the HTTP request path. Thus we
cannot pass the CLI args "json timeline" in conjunction with a "command"
string of "wiki" this way.

***HOWEVER...***

Much of the existing JSON code was written before the `--json-input`
option was possible. Because of this, there might be some
"misinteractions" when providing request-specific options via *both*
CLI options and simulated POST data. Those cases will eventually be
ironed out (with CLI options taking precedence). Until then, when
"POSTing" data in CLI mode, for consistent/predictible results always
provide any options via the JSON request data, not CLI arguments. That
said, there "should not" be any blatant incompatibilities, but some
routines will prefer `POST.payload` over CLI/GET arguments, so there
are some minor inconsistencies across various commands with regards to
which source (POST/GET/CLI) takes precedence for a given option. The
precedence "should always be the same," but currently cannot be due to
core fossil implementation details (the internal consolidation of
GET/CLI/POST vars into a single set).


<a id="json-indentation"></a>
# Indentation/Formatting of JSON Output

CLI mode accepts the `--indent|-I #` option to set the indention level
and HTTP mode accepts `indent=#` as a GET/POST parameter. The semantics
of the indention level are derived from the underlying JSON library and
have the following meanings: 0 (zero) or less disables all superfluous
indentation (this is the default in HTTP mode). A value of 1 uses 1 hard
TAB character (ASCII 0x09) per level of indention (the default in CLI
mode). Values greater than 1 use that many whitespaces (ASCII 32d) per
level of indention. e.g. a value of 7 uses 7 spaces per level of
indention. There is no way to specify one whitespace per level, but if
you *really* want one whitespace instead of one tab (same data size) you
can filter the output to globally replace ASCII 9dec (TAB) with ASCII
32dec (space). Because JSON string values *never* contain hard tabs
(they are represented by `\t`) there is no chance that such a global
replacement will corrupt JSON string contents - only the formatting will
be affected.

Potential TODO: because extraneous indention "could potentially" be used
as a form DoS, the option *might* be subject to later removed from HTTP
mode (in CLI it's fine).

In HTTP mode no trailing newline is added to the output, whereas in CLI
mode one is normally appended (exception: in JSONP mode no newline is
appended, to (rather pedantically and arbitraily) allow the client to
add a semicolon at the end if he likes). There is currently no option to
control the newline behaviour, but the underlying JSON code supports
this option, so adding it to this API is just a matter of adding the
CLI/HTTP args for it.

Pedantic note: internally the indention level is stored as a single
byte, so giving large indention values will cause harmless numeric
overflow (with only cosmetic effects), meaning, e.g., 257 will overflow
to the value 1.

Potential TODO: consider changing cson's indention mechanism to use a
*signed* number, using negative values for tabs and positive for
whitespace count (or the other way around). This would require more
doc changes than code changes :/.


<a id="jsonp"></a>
# JSONP

The API supports JSONP-style output. The caller specifies the callback
name and the JSON response will be wrapped in a function call to that
name. For HTTP mode pass the `jsonp=string` option (via GET or POST
envelope) and for CLI use `--jsonp string`.

For example, if we pass the JSONP name `myCallback` then a response will
look like:

```js
myCallback({...response...})
```

Note that fossil does not evaluate the callback name itself, other than
to verify that it is-a string, so "garbage in, garbage out," and all
that. (Remember that CLI and GET parameters are *always* strings, even
if they *look* like numbers.)


<a id="result-codes"></a>
# API Result Codes

Result codes are strings which tell the client whether or not a given
API call succeeded or failed, and if it failed *perhaps* some hint as to
why it failed.

The result code is available via the resultCode property of every
*error* response envelope. Since having a result code value for success
responses is somewhat redundant, success responses contain no resultCode
property. In practice this simplifies error checking on the client side.

The codes are strings in the form `FOSSIL-####`, where `####` is a
4-digit integral number, left-padded with zeros. The numbers follow
these conventions:

-   The number 0000 is reserved for the "not an error" (OK) case. Since
    success responses do not contain a result code, clients won't see
    this value (except in documentation).
-   All numbers with a leading 0 are reserved for *potential* future use
    in reporting non-fatal warnings.
-   Despite *possibly* having leading zeros, the numbers are decimal,
    not octal. Script code which uses eval() or similar to produce
    integers from them may need to take that into account.
-   The 1000ths and 100ths places of the number describe the general
    category of the error, e.g. authentication- vs. database- vs. usage
    errors. The 100ths place is more specific than the 1000ths place,
    allowing two levels of sub-categorization (which "should be enough"
    for this purpose). This separation allows the server administrator
    to configure the level of granularity of error reporting. e.g. some
    admins consider error messages to be security-relevant and like to
    "dumb them down" on their way to the client, whereas developers
    normally want to see very specific error codes when tracking down a
    problem. We can offer a configuration option to "dumb down" error
    codes to their generic category by simply doing a modulo 100
    (or 1000) against the native error code number. e.g. FOSSIL-1271
    could (via a simple modulo) be reduced to FOSSIL-1200 or
    FOSSIL-1000, depending on the paranoia level of the sysadmin. i have
    tried to order the result code numbers so that a dumb-down level of
    2 provides reasonably usable results without giving away too much
    detail to malicious clients.\
    (**TODO:** `g.json.errorDetailParanoia` is used to set the
    default dumb-down level, but it is currently set at compile-time.
    It needs to be moved to a config option. We have a chicken/egg scenario
    with error reporting and db access there (where the config is
    stored).)
-   Once a number is assigned to a given error condition (and actually
    used somewhere), it may not be changed/redefined. JSON clients need
    to be able to rely on stable result codes in order to provide
    adequate error reporting to their clients, and possibly for some
    error recovery logic as well (i.e. to decide whether to abort or
    retry).

The *tentative* list of result codes is shown in the following table.
These numbers/ranges are "nearly arbitrarily" chosen except for the
"special" value 0000.

**Maintenance reminder:** these codes are defined in
[`src/json_detail.h`](/finfo/src/json_detail.h) (enum
`FossilJsonCodes`) and assigned default `resultText` values in
[`src/json.c:json_err_cstr()`](/finfo/src/json.c). Changes there need
to be reflected here (and vice versa). Also, we have assertions in
place to ensure that C-side codes are in the range 1000-9999, so do
not just go blindly change the numeric ranges used by the enum.


**`FOSSIL-0###`: Non-error Category**

- `FOSSIL-0000`: Success/not an error. Succesful responses do not
  contain a resultCode, so clients should never see this.
- `FOSSIL-0###`: Reserved for potential future use in reporting
  non-fatal warnings.



**`FOSSIL-1000`: Generic Errors Category**

- `FOSSIL-1101`: Invalid request. Request envelope is invalid or
  missing.
- `FOSSIL-1102`: Unknown JSON command.
- `FOSSIL-1103`: Unknown/unspecified error
- `FOSSIL-1104`: RE-USE
- `FOSSIL-1105`: A server-side timeout was reached. (i’m not sure we
  can actually implement this one, though.)
- `FOSSIL-1106`: Assertion failed (or would have had we
  continued). Note: if an `assert()` fails in CGI/server modes, the HTTP
  response will be code 500 (Internal Server Error). We want to avoid
  that and return a JSON response instead. All of that said - there seems
  to be little reason to implementi this, since assertions are "truly
  serious" errors.
- `FOSSIL-1107`: Allocation/out of memory error. This cannot be reasonably
  reported because fossil aborts if an allocation fails.
- `FOSSIL-1108`: Requested API is not yet implemented.
- `FOSSIL-1109`: Panic! Fossil's `fossil_panic()` or `cgi_panic()` was
  called. In non-JSON HTML mode this produces an HTTP 500
  error. Clients "should" report this as a potential bug, as it
  "possibly" indicates that the C code has incorrect argument- or
  error handling somewhere.
- `FOSSIL-1110`: Reading of artifact manifest failed. Time to contact
  your local fossil guru.
- `FOSSIL-1111`: Opening of file failed (e.g. POST data provided to
  CLI mode).


**`FOSSIL-2000`: Authentication/Access Error Category**

- `FOSSIL-2001`: Privileged request was missing authentication
  token/cookie.
- `FOSSIL-2002`: Access to requested resource was denied. Oftentimes
  the `resultText` property will contain a human-language description of
  the access rights needed for the given command.
- `FOSSIL-2003`: Requested command is not available in the current
  operating mode. Returned in CLI mode by commands which require HTTP
  mode (e.g. login), and vice versa. FIXME: now that we can simulate
  POST in CLI mode, we can get rid of this distinction for some of the
  commands.
- `FOSSIL-2100`: Login Failed.
- `FOSSIL-2101`: Anonymous login attempt is missing the
  "anonymousSeed" property (fetched via [the `/json/anonymousPassword`
  request](api-auth.md#login-anonymous)). Note that this is more
  specific form of `FOSSIL-3002`.


ONLY FOR TESTING purposes should the remaning 210X sub-codes be
enabled (they are potentially security-relevant, in that the client
knows which part of the request was valid/invalid):

- `FOSSIL-2102`: Name not supplied in login request
- `FOSSIL-2103`: Password not supplied in login request
- `FOSSIL-2104`: No name/password match found


**`FOSSIL-3000`: Usage Error Category**

- `FOSSIL-3001`: Invalid argument/parameter type(s) or value(s) in
  request
- `FOSSIL-3002`: Required argument(s)/parameter(s) missing from
  request
- `FOSSIL-3003`: Requested resource identifier is ambiguous (e.g. a
  shortened UUID can be ambiguous).
- `FOSSIL-3004`: Unresolved resource identifier. A branch/tag/uuid
  provided by client code could not be resolved. This is a special
  case of #3006.
- `FOSSIL-3005`: Resource already exists and overwriting/replacing is
  not allowed. e.g. trying to create a wiki page or user which already
  exists. FIXME? Consolidate this and resource-not-found into a
  separate category for dumb-down purposes?
- `FOSSIL-3006`: Requested resource not found. e.g artifact ID, branch
  name, etc.


**`FOSSIL-4000`: Database-related Error Category**

- `FOSSIL-4001`: Statement preparation failed.
- `FOSSIL-4002`: Parameter binding failed.
- `FOSSIL-4003`: Statement execution failed.
- `FOSSIL-4004`: Database locked (this is not used anywhere, but
  reserved for future use).

Special-case DB-related errors...

- `FOSSIL-4101`: Fossil Schema out of date (repo rebuild required).
- `FOSSIL-4102`: Fossil repo db could not be found.
- `FOSSIL-4103`: Repository db is not valid (possibly corrupt).
- `FOSSIL-4104`: Check-out not found. This is similar to FOSSIL-4102
  but indicates that a local checkout is required (but was not
  found). Note that the 4102 gets triggered earlier than this one, and
  so can appear in cases when a user might otherwise expect a 4104
  error.


Some of those error codes are of course "too detailed" for the client to
do anything with (e.g.. 4001-4004), but their intention is to make it
easier for Fossil developers to (A) track down problems and (B) support
clients who report problems. If a client reports, "I get a FOSSIL-4000,
how can I fix it?" then the developers/support personnel can't say much
unless they know if it's a 4001, 4002, 4003, 4004, or 4101 (in which
case they can probably zero in on the problem fairly quickly, since they
know which API call triggered it and they know (from the error code) the
general source of the problem).

## Why Standard/Immutable Result Codes are Important

-   They are easily internationalized (i.e. associated with non-English
    error text)
-   Clients may be able to add automatic retry strategies for certain
    problem types by examining the result code. e.g. if fossil returns a
    locking or timeout error \[it currently does no special
    timeout/locking handling, by the way\] the client could re-try,
    whereas a usage error cannot be sensibly retried with the same
    inputs.
-   The "category" structure described above allows us some degree of
    flexibility in how detailed the reported errors are reported.
-   While the string prefix "FOSSIL-" on the error codes may seem
    superfluous, it has one minor *potential* advantage on the client
    side: when managing several unrelated data sources, these error
    codes can be immediately identified (by higher-level code which may
    be ignorant of the data source) as having come from the fossil API.
    Think "ORA-111" vs. "111".
Added www/json-api/hacking.md.


































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
# JSON API: Hacker's Guide
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Before Committing Changes](#before-committing)
* [JSON C API](#json-c-api)
* [Reporting Errors](#reporting-errors)
* [Getting Command Arguments](#command-args)
* [Creating JSON Data](#creating-json)
    * [Creating JSON Values](#creating-json-values)
    * [Converting SQL Query Results to JSON](#query-to-json)

This section will only be of interest to those wanting to work on the
Fossil/JSON code. That said...

If you happen to hack on the code and find something worth noting here
for others, please feel free to expand this section. It will only
improve via feedback from those working on the code.

---

<a id="before-committing"></a>
# Before Committing Changes...

Because this code lives in the trunk, there are certain
guidelines which must be followed before committing any changes:

1.  Read the [checkin preparation list](/doc/trunk/www/checkin.wiki).
2.  Changes to the files `src/json_*.*`, and its related support code
    (e.g. `ajax/*.*`), may be made freely without affecting mainline
    users. Changes to other files, unless they are trivial or made for
    purposes outside the JSON API (e.g. an unrelated bug fix), must be
    reviewed carefully before committing. When in doubt, create a branch
    and post a request for a review.
3.  The Golden Rule is: *do not break the trunk build*.


<a id="json-c-api"></a>
# JSON C API

libcson, the underlying JSON API, is a separate project, included in
fossil in "amalgamation" form: see `src/cson_amalgamation.[ch]`. It has
thorough API docs and a good deal of information is in its wiki:

[](https://fossil.wanderinghorse.net/wikis/cson/)

In particular:

[](https://fossil.wanderinghorse.net/wikis/cson/?page=CsonArchitecture)

gives an overview of its architecture. Occasionally new versions of it
are pulled into the Fossil tree, but other developers generally need not
concern themselves with that.

(Trivia: the cson wiki's back-end is fossil, living on top of a
JavaScript+HTML5 application.)

Only a small handful of low-level fossil routines actually input or
output JSON text (only for reading in POST data and sending the
response). In the C code we work with the higher-level JSON value
abstractions provided by cson (conceptually similar to an XML DOM). All
of the JSON-defined data types are supported, and we can construct JSON
output of near arbitrary complexity with the caveat that *cyclic data
structures are strictly forbidden*, and *will* cause memory corruption,
crashes, double free()'s, or other undefined behaviour. Because JSON
cannot, without client-specific semantic extensions to JSON, represent
cyclic structures, it is not anticipated that this will be a
problem/limitation when generating output for fossil.



<a id="json-commands"></a>
# Architecture of JSON Commands

In order to consolidate CLI/HTTP modes for JSON handling, this code
foregoes fossil's conventional command/path dispatching mechanism. Only
the top-most "json" command/path is dispatched directly by fossil's
core. The disadvantages of this are that we lose fossil's conventional
help text mechanism (which is based on code comments in the
command/path's dispatcher impl) and the ability to write abbreviated
command names in CLI mode ("json" itself may be abbreviated, but not the
subcommands). The advantages are that we can handle CLI/HTTP modes
almost identically (there are a couple minor differences) by unifying
them under the same callback functions much more easily.

The top-level "json" command/path uses its own dispatching mechanism
which uses either the path (in HTTP mode) or CLI positional arguments to
dispatch commands (stopping at the first "flag option" (e.g. -foo) in
CLI mode). The command handlers are simply callback functions which
return a cson\_value pointer (the C representation of an arbitrary JSON
value), representing the "payload" of the response (or NULL - not all
responses need a payload). On error these callbacks set the internal
JSON error state (detailed in a subsection below) and return NULL. The
top-level dispatcher then creates a response envelope and returns the
"payload" from the command (if any) to the caller. If a callback sets
the error state, the top-level dispatcher takes care to set the error
information in the response envelope. In summary:

-   The top-level dispatchers (`json_page_top()` and `json_cmd_top()`)
    are called by fossil's core when the "json" command/path is called.
    They initialize the JSON-mode global state, dispatch the requested
    command, and handle the creation of the response envelope. They
    prepare all the basic things which the individual subcommands need
    in order to function.
-   The command handlers (most are named `json_page_something()`)
    implement the `fossil_json_f()` callback interface (see
    [`src/json_detail.h`](/finfo/src/json_detail.h)). They are
    responsible for permissions checking, setting any error state, and
    passing back a payload (if needed - not all commands return a
    payload). It is strictly forbidden for these callbacks to produce
    any output on stdout/stderr, and doing so effectively corrupts the
    out-bound JSON and HTTP headers.

There is a wrench in all of that, however: the vast majority of fossil's
commands "fail fast" - they will `exit()` if they encounter an error. To
handle that, the fossil core error reporting routines have been
refactored a small bit to operate differently when we are running in
JSON mode. Instead of the conventional output, they generate a JSON
error response. In HTTP mode they exit with code 0 to avoid causing an
HTTP 500 error, whereas in CLI mode they will exit with a non-0 code.
Those routines still `exit()`, as in the conventional CLI/HTTP modes, but
they will exit differently. Because of this, it is perfectly fine for a
command handler to exit via one of fossil's conventional mechanisms
(e.g. `db_prepare()` can be fatal, and callbacks may call `fossil_panic()`
if they really want to). One exception is `fossil_exit()`, which does
_not_ generate any extra output and will `exit()` the app. In the JSON
API, as a rule of thumb, `fossil_exit()` is only used when we *want* a
failed request to cause an HTTP 500 error, and it is reserved for
allocation errors and similar truly catostrophic failures. That said...
libcson has been hacked to use `fossil_alloc()` and friends for memory
management, and those routines exit on error, so alloc error handling in
the JSON command handler code can afford to be a little lax (the
majority of *potential* errors clients get from the cson API have
allocation failure as their root cause).

As a side-note: the vast majority (if not all) of the cson API calls are
"NULL-safe", meaning that will return an error code (or be a no-op) if
passed NULL arguments. e.g. the following chain of calls will not crash
if the value we're looking for does not exist, is-not-a String (see
`cson_value_get_string()` for important details), or if `myObj` is NULL:

```c
const char * str =
 cson_string_cstr( // get the C-string form of a cson_string
   cson_value_get_string( // get its cson_string form
     cson_object_get(myObj,"foo") // search for key in an Object
   )
 );
```

If `"foo"` is not found in `myObj` (or if `myObj` is NULL) then v will be
NULL, as opposed to stepping on a NULL pointer somewhere in that call
chain.

Note that all cson JSON values except Arrays and Objects are *immutable*
- you cannot change a string's or number's value, for example. They also
use reference counting to manage ownership, as documented and
demonstrated on this page:

[](https://fossil.wanderinghorse.net/wikis/cson/?page=TipsAndTricks)

In short, after creating a new value you must eventually *either* add it
to a container (Object or Array) to transfer ownership *or* call
`cson_value_free()` to clean it up (exception: the Fossil/JSON command
callbacks *return* a value to transfer ownership to the dispatcher).
Sometimes it's more complex than that, but not normally. Any given value
may legally be stored in any number of containers (or multiple times
within one container), as long as *no cycles* are introduced (cycles
*will* cause undefined behaviour). Ownership is shared using reference
counting and the value will eventually be freed up when its last
remaining reference is freed (e.g. when the last container holding it is
cleaned up). For many examples of using cson in the context of fossil,
see the existing `json_page_xxx()` functions in `json_*.c`.

<a id="reporting-errors"></a>
# Reporting Errors

To report an error from a command callback, one abstractly needs to:

-   Set g.json.resultCode to one of the `FSL_JSON_E_xxx` values
    (defined in [`src/json_detail.h`](/finfo/src/json_detail.h)).
-   *Optionally* set `g.zErrMsg` to contain the (dynamically-allocated!)
    error string to be sent to the client. If no error string is set
    then a standard/generic string is used for the given error code.
-   Clean up any resources created so far by the handler.
-   Return NULL. If it returns non-NULL, the dispatcher will destroy the
    value and not include it in the error response.

That normally looks something like this:

```
if(!g.perm.Read){
  json_set_err(FSL_JSON_E_DENIED, "Requires 'o' permissions.");
  return NULL;
}
```

`json_set_err()` is a variadic printf-like function, and can use the
printf extensions supported by mprintf() and friends (e.g. `%Q` and `%q`)
(but they are normally not needed in the context of JSON). If the error
string is NULL or empty then `json_err_cstr(errorCode)` is used to fetch
the standard/generic error string for the given code.

When control returns to the top-level dispatching function it will check
`g.json.resultCode` and, if it is not 0, create an error response using
the `g.json.resultCode` and `g.zErrMsg` to construct the response's
`resultCode` and `resultText` properties.

If a function wants to output an error and exit by itself, as opposed
to returning to the dispatcher, then it must behave slightly
differently.  See the docs for `json_err()` (in
[`src/json.c`](/finfo/src/json.c)) for details, and search that file
for various examples of its usage. It is also used by fossil's core
error-reporting APIs, e.g. `fossil_panic()` (defined in [`src/main.c`](/finfo/src/main.c)).
That said, it would be "highly unusual" for a callback to need to do
this - it is *far* simpler (and more consistent/reliable) to set the
error state and return to the dispatcher.

<a id="command-args"></a>
# Getting Command Arguments

Positional parameters can be fetched usinig `json_command_arg(N)`, where
N is the argument position, with position 0 being the "json"
command/path. In CLI mode positional arguments have their obvious
meaning. In HTTP mode the request path (or the "command" request
property) is used to build up the "command path" instead. For example:

CLI: `fossil json a b c`

HTTP: `/json/a/b/c`

HTTP POST or CLI with `--json-input`: /json with POSTed envelope
`{"command": "a/b/c" …}`

Those will have identical "command paths," and `json_command_path(2)`
would return the "b" part.

Caveat: a limitation of this support is that all CLI flags must come
*after* all *non-flag* positional arguments (e.g. file names or
subcommand names). Any argument starting with a dash ("-") is considered
by this code to be a potential "flag" argument, and all arguments after
it are ignored (because the generic handling cannot know if a flag
requires an argument, which changes how the rest of the arguments need
to be interpreted).

To get named parameters, there are several approaches (plus some special
cases). Named parameters can normally come from any of the following
sources:

-   CLI arguments, e.g. `--foo bar`
-   GET parameters: `/json/...?foo=bar`
-   Properties of the POST envelope
-   Properties of the `POST.payload` object (if any).

To try to simplify the guessing process the API has a number of
functions which behave ever so slightly differently. A summary:

-   `json_getenv()` and `json_getenv_TYPE()` search the so-called "JSON
    environment," which is a superset of the GET/POST/`POST.payload` (if
    `POST.payload` is-a Object).
-   `json_find_option_TYPE()`: searches the CLI args (only when in CLI
    mode) and the JSON environment.
-   The use of fossil's `P()` and `PD()` macros is discourages in JSON
    callbacks because they can only handle String data from the CLI or
    GET parameters (not POST/`POST.payload`). (Note that `P()` and `PD()`
    *normally* also handle POSTed keys, but they only "see" values
    posted as form-urlencoded fields, and not JSON format.)
-   `find_option()` (from `src/main.c`) "should" also be avoided in
    JSON API handlers because it removes flag from the g.argv
    arguments list. That said, the JSON API does use `find_option()` in
    several of its option-finding convenience wrappers.

For example code: the existing command callbacks demonstrate all kinds
of uses and the various styles of parameter/option inspection. Check out
any of the functions named `json_page_SOMETHING()`.

<a href="creating-json"></a>
# Creating JSON Data

<a href="creating-json-values"></a>
## Creating JSON Values

cson has a fairly rich API for creating and manipulating the various
JSON-defined value types. For a detailed overview and demonstration i
recommend reading:

[](https://fossil.wanderinghorse.net/wikis/cson/?page=HowTo)

That said, the Fossil/JSON API has several convenience wrappers to save
a few bytes of typing:

-   `json_new_string("foo")` is easier to use than
    `cson_value_new_string("foo", 3)`, and
    `json_new_string_f("%s","foo")` is more flexible.
-   `json_new_int()` is easier to type than `cson_value_new_integer()`.
-   `cson_output_Blob()` and `cson_parse_Blob()` can write/read JSON
    to/from fossil `Blob`-type objects.

It also provides several lower-level JSON features which aren't of
general utility but provide necessary functionality for some of the
framework-level code (e.g. `cson_data_dest_cgi()`), which is only used
by the deepest of the JSON internals).


<a href="query-to-json"></a>
## Converting SQL Query Results to JSON

The `cson_sqlite3_xxx()` family of functions convert `sqlite3_stmt` rows
to Arrays or Objects, or convert single columns to a JSON-compatible
form. See `json_stmt_to_array_of_obj()`,
`json_stmt_to_array_of_array()` (both in `src/json.c`), and
`cson_sqlite3_column_to_value()` and friends (in
`src/cson_amalgamation.h`). They work in an intuitive way for numeric
types, but they optimistically/natively *assume* that any fields of type
TEXT or BLOB are actually UTF8 data, and treat them as such. cson's
string class only handles UTF8 data and it is semantically illegal to
feed them anything but UTF8. Violating this will likely result in
down-stream errors (e.g. when emiting the JSON string output). **The
moral of this story is:** *do not use these APIs to fetch binary data*.
JSON doesn't do binary and the `cson_string` class does not
protect itself against clients feeding it non-UTF8 data.

Here's a basic example of using these features:

```c
Stmt q = empty_Stmt;
cson_value * rows = NULL;
db_prepare(&q, "SELECT a AS a, b AS b, c AS c FROM foo");
rows = json_stmt_to_array_of_obj( &sql, NULL );
db_finalize(&q);
// side note: if db_prepare()/finalize() fail (==they exit())
// then a JSON-format error reponse will be generated.
```

On success (and if there were results), `rows` is now an Array value,
each entry of which contains an Object containing the fields (key/value
pairs) of each row. `json_stmt_to_array_of_array()` returns each row
as an Array containing the column values (with no column name
information).

**Note the seemingly superfluous use of the "AS" clause in the above
SQL.** Having them is actually significant! If a query does *not* use AS
clauses, the row names returned by the db driver *might* be different
than they appear in the query (this is documented behaviour of sqlite3).
Because the JSON API needs to return stable field names, we need to use
AS clauses to be guaranteed that the db driver will return the column
names we want. Note that the AS clause is often used to translate column
names into something more JSON-conventional or user-friendly, e.g.
"SELECT cap AS capabilities...". Alternately, we can convert the
individual `sqlite3_stmt` column values to JSON using
`cson_sqlite3_column_to_value()`, without refering directly to the
db-reported column name.
Added www/json-api/index.md.














































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# JSON API Index

This is the client-side documentation of Fossil's JSON API.  The JSON
API aims to provide access to many of the primary fossil features via
AJAX-style interfaces.

* [Introduction](intro.md)
* [General API Conventions](conventions.md)
* [Tips &amp; Tricks](tips.md)
* [Hacking Guide](hacking.md)

General warnings regarding the APIs linked to in the following list:

- **NOTE** that request/response examples shown in the individual API
pages do not show [the standard request/response envelope](conventions.md)
(for brevity and sanity).
- **Achtung:** just because a given feature is described as being
implemented does not mean that the implementation is "final" - it may be
changed at any time until we find/implement useful APIs.

The APIs, alphabetically by category:

* [Artifact Info](api-artifact.md)
* [Authentication](api-auth.md)
* [Branches](api-branch.md)
* [Checkout Status](api-checkout.md)
* [Config](api-config.md)
* [Diffs](api-diff.md)
* [Directory Listing](api-dir.md)
* [File Info](api-finfo.md)
* [The Obligatory Misc. Category](api-misc.md)
* [Repository Stats](api-stat.md)
* [SQL Query](api-query.md)
* [Tags](api-tag.md)
* [Tickets](api-ticket.md)
* [Timeline](api-timeline.md)
* [User Management](api-user.md)
* [Version](api-version.md)
* [Wiki](api-wiki.md)
Added www/json-api/intro.md.
















































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# JSON API Introduction
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Why?](#why)
* [Building JSON Support](#builing)
* [Goals & Non-goals](#goals)
* [Potential Client-side Uses](#potential-uses)
* [Technical Problems and Considerations](#considerations)

---

<a id="why"></a>
# Why?

In September, 2011, Fossil contributor Stephan Beal had the great
pleasure of meeting D. Richard Hipp, Fossil's author, for lunch in
Munich, Germany. During the conversation Richard asked, "what does
Fossil need next?" Stephan's first answer was, "refactoring into a
library/client, as opposed to a monolithic app." We very quickly
agreed that the effort required would be "herculean," and second
choice was voiced, "a JSON API." They briefly discussed the idea and
Richard gave his blessing.  That night work began.

Why a JSON API? Because it is the next best thing to the
"librification" of Fossil, in that it makes Fossil's features
available to near-arbitrary applications using a simple, globally
available data format.

<a id="building"></a>
# Building JSON Support

In environments supported by fossil's `configure` script,
simply pass `--enable-json` to it:

```
$ ./configure --prefix=$HOME --enable-json ...
```

When built without that option, JSON support is disabled. **When
reconfiguring the source tree**, ***always be sure to do a "make
clean"*** (or equivalent for your platform) between builds (preferably
*before* reconfiguring), to ensure that everything is rebuilt properly.
If you fail to do that after enabling JSON on a tree which has already
been built, most of the sources will not be rebuilt properly. The reason
is that the JSON files are actually unconditionally compiled, but when
built without `--enable-json` they compile to empty object files. Thus
after a reconfigure the (empty) object files are still up-to-date
vis-a-vis the sources, and won't be rebuilt.

To build Fossil with JSON support on Windows using the Microsoft C
compiler:

```
cd win
nmake -f Makefile.msc FOSSIL_ENABLE_JSON=1
```

It has been seen to compile in VC versions 6 and higher.

<a id="goals"></a>
# Goals & Non-goals

The API described here is most certainly not
[*REST*](http://en.wikipedia.org/wiki/Representational_state_transfer)-conformant,
but is instead JSON over HTTP. The error reporting techniques of the
REST conventions (using HTTP error codes) "does not mesh" with my ideas
of separation of transport- vs. app-side errors. Additionally, REST
requires HTTP methods which are not specified by CGI (namely PUT and
DELETE), which means we can't possibly implement a REST-compatible
interface on top of fossil (which uses CGI mode even for its built-in
server).

The **overall goals** of this effort include:

-   A JSON-based API off of which clients can build customized Fossil
    UIs and special-purpose applications. e.g. a desktop notification
    applet which polls for new timeline data.
-   Arbitrary JSON-using clients should be able to use it. Though JSON
    originates from JavaScript, it is truly a cross-platform data format
    with a very high adoption rate. (There’s even a JSON implementation
    for Oracle PL/SQL.)
-   Fossil’s CGI and Server modes are the main targets and should be
    supported equally. CLI JSON mode is of secondary concern (but is in
    practice easier to test, so it’s generally implemented first).

The ***non-goals*** include:

-   We won’t be able to implement *every* feature of Fossil via a JSON
    interface, and we won’t try to.
-   Binary data (e.g. commits of binary files or downloading ZIP files)
    is not an initial goal, but "might be interesting" once the overall
    infrastructure is in place and working well. See below for more
    details about binary data in JSON.
-   A "pure REST" interface is seemingly not possible due to REST
    relying on HTTP methods not specified in the CGI standard (PUT and
    DELETE). Additionally, REST-style error reporting cannot be used by
    non-HTTP clients (which this code supports).

Adding JSON support also gives us a framework off of which to
build/enhance other features. Some examples include:

-   **Internationalization**. Errors are reported via standard codes and
    the raw artifact data is language-independent.
-   The ability to author **special-case clients**, e.g. a ticket
    poller.
-   Use **arbitrary HTTP-capable languages** to implement such tools.
    Programming languages which can execute programs and intercept their
    stdout output can use the JSON API via a local fossil binary.
-   **Automatable tests.** Many of fossil's test results currently have
    to be "visually reviewed" for correctness after changes (e.g.
    changes in the HTML interface). JSON structures can be
    programmatically checked for correctness. Artifacts are immutable,
    which allows us to be very specific in what data to expect as output
    (for artifact-specific requests the payload data will often (but not
    always) be the same across all requests and all time).

<a id="potential-uses"></a>
# Potential Client-side Uses

Some of the potential client-side uses of this API include...

-   Custom apps/applets to fetch timeline/ticket/etc. information from
    arbitrary repositories. There are many possibilities here, including
    "dashboard" sites which monitor several repositories.
-   Custom post-commit triggers, by polling for changes and reacting to
    them (e.g. sending mails).
-   A custom wiki front-end which uses fossil as the back-end storage,
    inheriting its versioning and user access support while providing a
    completely custom wiki-centric UI. Such a wiki need not have, on the
    surface, anything to do with fossil or source control, as fossil
    would just become a glorified wiki back-end. This approach also
    allows clients to serve wiki pages in a format of their choice -
    since all rendering would be done client-side, they could use
    whatever format they like.


<a id="considerations"></a>
# Technical Problems and Considerations

A random list of considerations which need to be made and potential
problem areas...

-   **Binary data:** HTML4 and JavaScript have no portable way of
    handling binary data, so commands which could potentially deal with
    binary data (e.g. committing a file) are ruled out for the time
    being. HTML5 and accompanying JavaScript additions will binary
    data usable client-side. That said, a JSON interface cannot natively
    work with binary unless it is encoded (base64 or hex or whatever),
    and such encoding would have to be understood on both the server and
    client sides, which may rule out usage in some environments.\
    **Status:** deferred until needed. My current thinking is to send
    URLs instead of binary data, and the URLs would point to some path
    which produces the raw artifact content. We could read POSTed binary
    input, but this might require some re-tooling of fossil's innards
    and it precludes the use of a JSON request envelope, so it would be
    limited to requests which can be configured solely via GET arguments
    (as opposed to POST envelope/payload options). i.e. configure the
    JSON bits via GET and POST the binary data.
-   **64-bit integers:** JSON does not specify integer precision,
    probably because it targets many different platforms and not all
    of them can support more than 32 bits. JavaScript (from which JSON
    derives) supports 53 bits of integer precision. That said, it's
    "highly unlikely" that we'll have any range problems with "only"
    53 bits of precision. The underlying JSON API supports *signed*
    32- or 64-bit integers on both 32- and 64-bit builds, but only if
    "long long" or `int64_t` are available (from the C99 header
    `stdint.h`). Only multi-gig repositories are ever expected to use
    large numbers, and even then only rarely (e.g. via the "stat"
    command).
-   **Timestamps:** for portability this API uses GMT Unix Epoch
    timestamps. They are the most portable time representation out
    there, easily usable in most programming environments. (In hindsight,
    this should have been Unix + Milliseconds, but the API already
    pervasively uses seconds-precision.)
-   **Artifact vs. Artefact:** both are correct vis-a-vis the
    english language but Fossil consistently uses the former, so we’ll
    use that.
-   **Multiple logins per user:** fossil currently does not allow
    multiple active logins for a given user except anonymous. For all
    others, the most recent login wins. This is only a very minor
    annoyance for the HTML interface but will be more problematic for
    JSON clients. e.g. a user might have a ticket poller and a commit poller
    running, and both would need to be logged in.\
    **Status:** as of 20120315 (commit
    [*73038baaa3*](http://www.fossil-scm.org/index.html/info/73038baaa3)),
    fossil allows a user to be logged in multiple times (confirm: only
    within the same network?). The only caveat is that if any one of
    them logs out, it will invalidate the login session for the others.
    This is good enough for the time being, however. It will likely only
    become painful if we actually get enough apps in the wild that
    someone might have some running on his mobile phone and some on his
    PC and some on his server. The workarounds for now are (A) not to
    log out and (B) program apps/applets/widgets to try to re-login
    occasionally. Fossil will at some point expire the login, anyway.
    FIXME: update the expiry time on each request? To do that right we'd
    have to re-set the cookie on each request :/. We could optionally
    add a new JSON request which simply updates the login cookie
    lifetime (e.g. /json/keepalive or expand /json/whoami to do that).
Added www/json-api/tips.md.












































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# JSON API: Tips and Tricks
([&#x2b11;JSON API Index](index.md))

Jump to:

* [Beware of Content-Type and Encoding...](#content-type)
  * [Using `curl` and `wget`](#curl-wget)
* [Example JavaScript](#javascript)
* [Demo Apps](#demo-apps)

---

<a id="content-type"></a>
# Beware of Content-Type and Encoding...

When posting data to fossil, make sure that the request sends:

-   **Content-Type** of `application/json`. Fossil also (currently)
    accepts `application/javascript` and `text/plain` as JSON input,
    but `application/json` is preferred. The client may optionally
    send `;charset=utf-8` with the Content-Type, but any other
    encoding produces undefined results. Behaviour without the charset
    or with `;charset=utf-8` suffix is identical.
-   **POST data must be an non-form-encoded JSON string**
    (ASCII or UTF-8). jQuery, by default, form-urlencodes it, which the
    fossil json bits cannot read. e.g. post the result of
    `JSON.stringify(requestObject)`, without any additional encoding on
    top of it.
-   **When POSTing via jQuery**, set these AJAX options:
    -   `contentType:'application/json'`
    -   `dataType:'text'`
    -   `data:JSON.stringify(requestObject)`
-   **When POSTing via XMLHttpRequest** (XHR), be sure to:
    -   `xhr.open( … )`
    -   `xhr.setRequestHeader("Content-Type", "application/json")`
    -   `xhr.send( JSON.stringify( requestObject ) )`

The response will be (except in the case of an HTTP 500 error or
similar) a JSON or JSONP string, ready to be parsed by your favourite
`JSON.parse()` implementation or `eval()`'d directly.

<a id="curl-wget"></a>
## Using `curl` and `wget`

Both [curl](https://curl.haxx.se/) and
[wget](https://www.gnu.org/software/wget/) can be used to post data to
this API from the command line or scripts, but both require an extra
parameter to set the request encoding.

Example:

```console
$ cat x.json
{
"payload": {
  "sql": "SELECT * FROM reportfmt limit 1",
  "format": "o"
  }
}

# Fossil has been started locally with:
#   fossil server --localauth
# which allows the following requests to work without extra
# authenticaion:

$ wget -q -O- \
  --post-file=x.json \
  --header="Content-Type: application/json" \
  'http://localhost:8080/json/query'

$ curl \
  --data-binary @x.json \
  --header 'Content-Type: application/json' \
  'http://localhost:8080/json/query'
```

The relevant parts for encoding are the `--header` flag for `wget` and
`curl`, noting that they have different syntaxes for each
(`--header=X` vs `--header X`).

<a id="javascript"></a>
# Example JavaScript (Browser and Shell)

In the fossil source tree, [in the ajax directory](/dir/ajax), is test/demo code
implemented in HTML+JavaScript. While it is still quite experimental, it
demonstrates one approach to creating client-side wrapper APIs for
remote Fossil/JSON repositories.

There is some additional JS test code, which uses the Rhino JS engine
(i.e. from the console, not the browser), under
[`ajax/i-test`](/dir/ajax/-itest). That adds a Rhino-based connection
back-end to the AJAJ API and uses it for running integration-style
tests against an arbitrary JSON-capable repository.


<a id="demo-apps"></a>
# Demo Apps

Known in-the-wild apps using this API:

-   The wiki browsers/editors at [](https://fossil.wanderinghorse.net/wikis/)

Changes to www/loadmgmt.md.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2.  Page requests can be configured to fail with a
    “[503 Server Overload][503]” HTTP error if an expensive request is
    received while the host load average is too high.

Both of these load-control mechanisms are turned off by default, but
they are recommended for high-traffic sites.

The webpage cache is activated using the [`fossil cache
init`](/help/cache) command-line on the server.  Add a `-R` option to
specify the specific repository for which to enable caching.  If running
this command as root, be sure to “`chown`” the cache database to give
the Fossil server write permission for the user ID of the web server;
this is a separate file in the same directory and with the same name as
the repository but with the “`.fossil`” suffix changed to “`.cache`”.

To activate the server load control feature visit the Admin → Access







|
|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2.  Page requests can be configured to fail with a
    “[503 Server Overload][503]” HTTP error if an expensive request is
    received while the host load average is too high.

Both of these load-control mechanisms are turned off by default, but
they are recommended for high-traffic sites.

The webpage cache is activated using the [`fossil cache init`](/help/cache)
command-line on the server.  Add a `-R` option to
specify the specific repository for which to enable caching.  If running
this command as root, be sure to “`chown`” the cache database to give
the Fossil server write permission for the user ID of the web server;
this is a separate file in the same directory and with the same name as
the repository but with the “`.fossil`” suffix changed to “`.cache`”.

To activate the server load control feature visit the Admin → Access
Added www/mdtest/test1.md.






















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# Markdown Link-test

This document exist solely as a test for some of the hyperlinking
capabilities of Markdown as implemented by Fossil.

## Relative-Path Links

  *   The index: [](../index.wiki)

  *   Load management: [](../loadmgmt.md)

  *   Site-map:  [](../../../../sitemap)

  *   Windows CGI: [](../server/windows/cgi.md)

## The Magic $ROOT Path Prefix

In text of the form `href="$ROOT/..."` in the HTML that markdown
generates, the $ROOT is replaced by the complete URI for the root 
of the document tree.
Note that the $ROOT translation only occurs within the `<a href="...">`
element, not within the text of the hyperlink.  So you should see the
$ROOT text on this page, but if you mouse-over the hyperlink the $ROOT
value should have been expanded to the actual document root.

  *   Timeline: []($ROOT/timeline)

  *   Site-map:  []($ROOT/sitemap)

The $ROOT prefix on markdown links is superfluous.  The same link
works without the $ROOT prefix.  (Though: the $ROOT prefix is required
for HTML documents.)

  *   Timeline:  [](/timeline)

  *   Help: [](/help?cmd=help)

  *   Site-map:  [](/sitemap)

## The Magic $CURRENT Document Version Translation

In URI text of the form `.../doc/$CURRENT/...` the
$CURRENT value is converted to the version number of the document
currently being displayed.  This conversion happens after translation
into HTML and only occurs on href='...' attributes so it does not occur
for plain text.

  *   Document index:  [](/doc/$CURRENT/www/index.wiki)

Both the $ROOT and the $CURRENT conversions can occur on the same link.

  *   Document index:  []($ROOT/doc/$CURRENT/www/index.wiki)

The translations must be contained within HTML markup in order to work.
They do not work for ordinary text that appears to be an href= attribute.

  *   `x href='$ROOT/timeline'`
  *   `x action="$ROOT/whatever"`
  *   `x href="https://some-other-site.com/doc/$CURRENT/tail"`
Changes to www/mirrorlimitations.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16












17
18
19
20
21
22
23

24

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

45
46
47
48
49
50
51








52
53
54
55
56
57
58
59
60
61
62
# Limitations On Git Mirrors

The "<tt>[fossil git export](/help?cmd=git)</tt>" command can be used to
mirror a Fossil repository to Git.
([Setup instructions](./mirrortogithub.md) and an
[example](https://github.com/drhsqlite/fossil-mirror).)
But the export to Git is not perfect. Some information is lost during
export due to limitations in Git.  This page describes what content of
Fossil is not included in an export to Git.

## (1) Wiki, Tickets, Technotes, Forum

Git only supports version control. The additional features of Fossil such
as Wiki, Tickets, Technotes, and the Forum are not supported in Git and
so those features are not included in an export.













## (2) Cherrypick Merges

The Git client supports cherrypick merges but does not remember them.
In other words, Git does not record a history of cherrypick merges
in its blockchain.

Fossil tracks cherrypick merges in its blockchain and display cherrypicks

(as dashed lines) in its timeline ([example](/timeline?c=0a9f12ce6655b7a5)).

But history information of cherrypicks cannot be exported to Git because
there is no way to represent it in the Git.

## (3) Named Branches

Git has only limited support for named branches.  Git identifies the head
check-in of each branch.  Depending on the check-in graph topology, this
is sufficient to infer the branch for many historical check-ins as well.
However, complex histories with lots of cross-merging
can lead to ambiguities.  Fossil keeps
track of historical branch names unambiguously. 
But the extra details about branch names that Fossil keeps
at hand cannot be exported to Git.

## (4) Non-unique Tags

Git requires tags to be unique.  Each tag must refer to exactly one
check-in.  Fossil does not have this restriction, and so it is common
in Fossil to tag multiple check-ins with the same name.  For example,
it is common in Fossil to tag every release check-in with the "release"

tag, so that all historical releases can be found all at once.
([example](/timeline?t=release))

Git does not allow this.  The "release" tag must refer to just one
check-in.  The work-around is that the non-unique tag in the Git export is 
made to refer to only the most recent check-in with that tag.









## (5) Amendments To Check-ins

Check-ins are immutable in both Fossil and Git.
However, Fossil has a mechanism by which tags can be added
its blockchain to provide after-the-fact corrections to prior check-ins.

For example, tags can be added to check-ins that correct typos in the
check-in comment.  The original check-in is immutable and so the
original comment is preserved in addition to the correction. But
software that displays the check-ins knows to look for the comment-change
tag and if present displays the corrected comment rather than the original.













|


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


|
|
<

|
>
|
>
|
|








|
|




|


|
>
|
|





>
>
>
>
>
>
>
>



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# Limitations On Git Mirrors

The "<tt>[fossil git export](/help?cmd=git)</tt>" command can be used to
mirror a Fossil repository to Git.
([Setup instructions](./mirrortogithub.md) and an
[example](https://github.com/drhsqlite/fossil-mirror).)
But the export to Git is not perfect. Some information is lost during
export due to limitations in Git.  This page describes what content of
Fossil is not included in an export to Git.

## (1) Wiki, Tickets, Technotes, Forum

Git only supports version control. The additional features of Fossil such
as Wiki, Tickets, Technotes, and the Forum are not supported in Git,
so those features are not included in an export.

Third-party Git based tooling may add some of these features (e.g.
GitHub, GitLab) but because their data are not stored in the Git
blockchain, there is no single destination for Fossil to convert its
equivalent data *to*. For instance, Fossil tickets do not become GitHub
issues, because that is a proprietary feature of GitHub separate from
Git proper, stored outside the blockchain on the GitHub servers.

You can also see the problem in its inverse case: you do not get a copy
of your GitHub issues when cloning the Git repository. You *do* get the
Fossil tickets, wiki, forum posts, etc. when cloning a remote Fossil
repo.

## (2) Cherrypick Merges

The Git client supports cherrypick merges but does not record the
cherrypick parent(s).


Fossil tracks cherrypick merges in its blockchain and displays
cherrypicks in its timeline. (As an example, the dashed lines
[here](/timeline?c=0a9f12ce6655b7a5) are cherrypicks.) Because Git does
not have a way to represent this same information in its blockchain, the
history of Fossil cherrypicks cannot be exported to Git, only their
direct effects on the managed file data.

## (3) Named Branches

Git has only limited support for named branches.  Git identifies the head
check-in of each branch.  Depending on the check-in graph topology, this
is sufficient to infer the branch for many historical check-ins as well.
However, complex histories with lots of cross-merging
can lead to ambiguities.  Fossil keeps
track of historical branch names unambiguously, 
but the extra details about branch names that Fossil keeps
at hand cannot be exported to Git.

## (4) Non-unique Tags

Git requires tags to be unique: each tag must refer to exactly one
check-in.  Fossil does not have this restriction, and so it is common
in Fossil to tag multiple check-ins with the same name.  For example,
it is common in Fossil to tag each check-in creating a release both
with a unique version tag *and* a common tag like "release"
so that all historical releases can be found at once.
([Example](/timeline?t=release).)

Git does not allow this.  The "release" tag must refer to just one
check-in.  The work-around is that the non-unique tag in the Git export is 
made to refer to only the most recent check-in with that tag.

This is why the ["release" tag view][ghrtv] in the GitHub mirror of this
repository shows only the latest release version; contrast the prior
example. Both URLs are asking the repository the same question, but
because of Git's relatively impoverished data model, it cannot give the
same answer that Fossil does.

[ghrtv]: https://github.com/drhsqlite/fossil-mirror/tree/release

## (5) Amendments To Check-ins

Check-ins are immutable in both Fossil and Git.
However, Fossil has a mechanism by which tags can be added to
its blockchain to provide after-the-fact corrections to prior check-ins.

For example, tags can be added to check-ins that correct typos in the
check-in comment.  The original check-in is immutable and so the
original comment is preserved in addition to the correction. But
software that displays the check-ins knows to look for the comment-change
tag and if present displays the corrected comment rather than the original.
Changes to www/mkindex.tcl.
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

53
54

55
56
57

58
59
60
61
62
63
64
  changes.wiki {Fossil Changelog}
  checkin_names.wiki {Check-in And Version Names}
  checkin.wiki {Check-in Checklist}
  childprojects.wiki {Child Projects}
  copyright-release.html {Contributor License Agreement}
  concepts.wiki {Fossil Core Concepts}
  contribute.wiki {Contributing Code or Documentation To The Fossil Project}

  customgraph.md {Theming: Customizing the Timeline Graph}
  customskin.md {Theming: Customizing The Appearance of Web Pages}
  customskin.md {Custom Skins}
  custom_ticket.wiki {Customizing The Ticket System}
  defcsp.md {The Default Content Security Policy}
  delta_encoder_algorithm.wiki {Fossil Delta Encoding Algorithm}
  delta_format.wiki {Fossil Delta Format}
  embeddeddoc.wiki {Embedded Project Documentation}
  encryptedrepos.wiki {How To Use Encrypted Repositories}
  env-opts.md {Environment Variables and Global Options}
  event.wiki {Events}
  faq.wiki {Frequently Asked Questions}
  fileformat.wiki {Fossil File Format}
  fiveminutes.wiki {Up and Running in 5 Minutes as a Single User}
  forum.wiki {Fossil Forums}
  foss-cklist.wiki {Checklist For Successful Open-Source Projects}
  fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
  fossil_prompt.wiki {Fossilized Bash Prompt}
  fossil-v-git.wiki {Fossil Versus Git}
  globs.md {File Name Glob Patterns}

  grep.md {Fossil grep vs POSIX grep}
  hacker-howto.wiki {Hacker How-To}

  hashpolicy.wiki {Hash Policy: Choosing Between SHA1 and SHA3-256}
  /help {Lists of Commands and Webpages}
  hints.wiki {Fossil Tips And Usage Hints}

  index.wiki {Home Page}
  inout.wiki {Import And Export To And From Git}
  image-format-vs-repo-size.md {Image Format vs Fossil Repo Size}
  javascript.md {Use of JavaScript in Fossil}
  makefile.wiki {The Fossil Build Process}
  mirrorlimitations.md {Limitations On Git Mirrors}
  mirrortogithub.md {How To Mirror A Fossil Repository On GitHub}







>




















>


>



>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  changes.wiki {Fossil Changelog}
  checkin_names.wiki {Check-in And Version Names}
  checkin.wiki {Check-in Checklist}
  childprojects.wiki {Child Projects}
  copyright-release.html {Contributor License Agreement}
  concepts.wiki {Fossil Core Concepts}
  contribute.wiki {Contributing Code or Documentation To The Fossil Project}
  css-tricks.md {Fossil CSS Tips and Tricks}
  customgraph.md {Theming: Customizing the Timeline Graph}
  customskin.md {Theming: Customizing The Appearance of Web Pages}
  customskin.md {Custom Skins}
  custom_ticket.wiki {Customizing The Ticket System}
  defcsp.md {The Default Content Security Policy}
  delta_encoder_algorithm.wiki {Fossil Delta Encoding Algorithm}
  delta_format.wiki {Fossil Delta Format}
  embeddeddoc.wiki {Embedded Project Documentation}
  encryptedrepos.wiki {How To Use Encrypted Repositories}
  env-opts.md {Environment Variables and Global Options}
  event.wiki {Events}
  faq.wiki {Frequently Asked Questions}
  fileformat.wiki {Fossil File Format}
  fiveminutes.wiki {Up and Running in 5 Minutes as a Single User}
  forum.wiki {Fossil Forums}
  foss-cklist.wiki {Checklist For Successful Open-Source Projects}
  fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
  fossil_prompt.wiki {Fossilized Bash Prompt}
  fossil-v-git.wiki {Fossil Versus Git}
  globs.md {File Name Glob Patterns}
  gitusers.md {Hints For Users With Git Experience}
  grep.md {Fossil grep vs POSIX grep}
  hacker-howto.wiki {Hacker How-To}
  hacker-howto.wiki {Fossil Developers Guide}
  hashpolicy.wiki {Hash Policy: Choosing Between SHA1 and SHA3-256}
  /help {Lists of Commands and Webpages}
  hints.wiki {Fossil Tips And Usage Hints}
  history.md {The Purpose And History Of Fossil}
  index.wiki {Home Page}
  inout.wiki {Import And Export To And From Git}
  image-format-vs-repo-size.md {Image Format vs Fossil Repo Size}
  javascript.md {Use of JavaScript in Fossil}
  makefile.wiki {The Fossil Build Process}
  mirrorlimitations.md {Limitations On Git Mirrors}
  mirrortogithub.md {How To Mirror A Fossil Repository On GitHub}
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
<input type="text" name="s" size="40" autofocus>
<input type="submit" value="Search Docs">
</form>
</center>
<h2>Primary Documents:</h2>
<ul>
<li> <a href='quickstart.wiki'>Quick-start Guide</a>
<li> <a href='faq.wiki'>FAQ</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>



<li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
book</a>
<li> <a href='$ROOT/help'>List of commands, web-pages, and settings</a>
<li> <a href='hacker-howto.wiki'>Hacker How-To</a>
</ul>
<a name="pindex"></a>
<h2>Permuted Index:</h2>
<ul>}
foreach entry $permindex {
  foreach {title file bold} $entry break
  if {$bold} {set title <b>$title</b>}
  if {[string match /* $file]} {set file ../../..$file}
  puts $out "<li><a href=\"$file\">$title</a></li>"
}
puts $out "</ul></div>"







|


>
>
>


<
<











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
<input type="text" name="s" size="40" autofocus>
<input type="submit" value="Search Docs">
</form>
</center>
<h2>Primary Documents:</h2>
<ul>
<li> <a href='quickstart.wiki'>Quick-start Guide</a>
<li> <a href='history.md'>Purpose and History of Fossil</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
<li> <a href='$ROOT/help'>List of commands, web-pages, and settings</a>
<li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
<li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
book</a>


</ul>
<a name="pindex"></a>
<h2>Permuted Index:</h2>
<ul>}
foreach entry $permindex {
  foreach {title file bold} $entry break
  if {$bold} {set title <b>$title</b>}
  if {[string match /* $file]} {set file ../../..$file}
  puts $out "<li><a href=\"$file\">$title</a></li>"
}
puts $out "</ul></div>"
Changes to www/permutedindex.html.
1
2
3
4
5
6
7
8
9
10
11
12
13
14



15
16
17
18
19
20
21
22
23
24
25
<div class='fossil-doc' data-title='Index Of Fossil Documentation'>

<center>
<form action='$ROOT/docsrch' method='GET'>
<input type="text" name="s" size="40" autofocus>
<input type="submit" value="Search Docs">
</form>
</center>
<h2>Primary Documents:</h2>
<ul>
<li> <a href='quickstart.wiki'>Quick-start Guide</a>
<li> <a href='faq.wiki'>FAQ</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>



<li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
book</a>
<li> <a href='$ROOT/help'>List of commands, web-pages, and settings</a>
<li> <a href='hacker-howto.wiki'>Hacker How-To</a>
</ul>
<a name="pindex"></a>
<h2>Permuted Index:</h2>
<ul>
<li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Up and Running in</a></li>
<li><a href="fossil-from-msvc.wiki">2010 IDE &mdash; Integrating Fossil in the Microsoft Express</a></li>
<li><a href="tech_overview.wiki"><b>A Technical Overview Of The Design And Implementation Of Fossil</b></a></li>











|


>
>
>


<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


20
21
22
23
24
25
26
<div class='fossil-doc' data-title='Index Of Fossil Documentation'>

<center>
<form action='$ROOT/docsrch' method='GET'>
<input type="text" name="s" size="40" autofocus>
<input type="submit" value="Search Docs">
</form>
</center>
<h2>Primary Documents:</h2>
<ul>
<li> <a href='quickstart.wiki'>Quick-start Guide</a>
<li> <a href='history.md'>Purpose and History of Fossil</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
<li> <a href='$ROOT/help'>List of commands, web-pages, and settings</a>
<li> <a href='userlinks.wiki'>Key Docs for Fossil Users</a>
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
<li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
book</a>


</ul>
<a name="pindex"></a>
<h2>Permuted Index:</h2>
<ul>
<li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Up and Running in</a></li>
<li><a href="fossil-from-msvc.wiki">2010 IDE &mdash; Integrating Fossil in the Microsoft Express</a></li>
<li><a href="tech_overview.wiki"><b>A Technical Overview Of The Design And Implementation Of Fossil</b></a></li>
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88
89
90
91
92
93

94
95
96
97
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

142
143
144
145
146
147
148
149

150
151
152
153
154
155
156


157
158
159
160
161
162
163
<li><a href="contribute.wiki"><b>Contributing Code or Documentation To The Fossil Project</b></a></li>
<li><a href="copyright-release.html"><b>Contributor License Agreement</b></a></li>
<li><a href="whyusefossil.wiki">Control &mdash; Benefits Of Version</a></li>
<li><a href="concepts.wiki">Core Concepts &mdash; Fossil</a></li>
<li><a href="newrepo.wiki">Create A New Fossil Repository &mdash; How To</a></li>
<li><a href="private.wiki"><b>Creating, Syncing, and Deleting Private Branches</b></a></li>
<li><a href="qandc.wiki">Criticisms &mdash; Questions And</a></li>

<li><a href="customskin.md"><b>Custom Skins</b></a></li>
<li><a href="customskin.md">Customizing The Appearance of Web Pages &mdash; Theming:</a></li>
<li><a href="custom_ticket.wiki"><b>Customizing The Ticket System</b></a></li>
<li><a href="customgraph.md">Customizing the Timeline Graph &mdash; Theming:</a></li>
<li><a href="tech_overview.wiki">Databases Used By Fossil &mdash; SQLite</a></li>
<li><a href="defcsp.md">Default Content Security Policy &mdash; The</a></li>
<li><a href="antibot.wiki"><b>Defense against Spiders and Bots</b></a></li>
<li><a href="shunning.wiki">Deleting Content From Fossil &mdash; Shunning:</a></li>
<li><a href="private.wiki">Deleting Private Branches &mdash; Creating, Syncing, and</a></li>
<li><a href="delta_encoder_algorithm.wiki">Delta Encoding Algorithm &mdash; Fossil</a></li>
<li><a href="delta_format.wiki">Delta Format &mdash; Fossil</a></li>
<li><a href="tech_overview.wiki">Design And Implementation Of Fossil &mdash; A Technical Overview Of The</a></li>
<li><a href="theory1.wiki">Design Of The Fossil DVCS &mdash; Thoughts On The</a></li>

<li><a href="caps/admin-v-setup.md"><b>Differences Between Setup and Admin Users</b></a></li>
<li><a href="embeddeddoc.wiki">Documentation &mdash; Embedded Project</a></li>
<li><a href="contribute.wiki">Documentation To The Fossil Project &mdash; Contributing Code or</a></li>
<li><a href="aboutdownload.wiki">Download Page Works &mdash; How The</a></li>
<li><a href="theory1.wiki">DVCS &mdash; Thoughts On The Design Of The Fossil</a></li>
<li><a href="quotes.wiki">DVCSes in General &mdash; Quotes: What People Are Saying About Fossil, Git, and</a></li>
<li><a href="alerts.md"><b>Email Alerts And Notifications</b></a></li>
<li><a href="embeddeddoc.wiki"><b>Embedded Project Documentation</b></a></li>
<li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &mdash; Fossil Delta</a></li>
<li><a href="encryptedrepos.wiki">Encrypted Repositories &mdash; How To Use</a></li>
<li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li>
<li><a href="event.wiki"><b>Events</b></a></li>
<li><a href="webpage-ex.md">Examples &mdash; Webpage</a></li>

<li><a href="inout.wiki">Export To And From Git &mdash; Import And</a></li>
<li><a href="fossil-from-msvc.wiki">Express 2010 IDE &mdash; Integrating Fossil in the Microsoft</a></li>
<li><a href="serverext.wiki">Extensions &mdash; CGI Server</a></li>
<li><a href="serverext.wiki">Extensions To A Fossil Server Using CGI Scripts &mdash; Adding</a></li>
<li><a href="adding_code.wiki">Features To Fossil &mdash; Adding New</a></li>
<li><a href="fileformat.wiki">File Format &mdash; Fossil</a></li>
<li><a href="globs.md"><b>File Name Glob Patterns</b></a></li>
<li><a href="unvers.wiki">Files &mdash; Unversioned</a></li>
<li><a href="branching.wiki">Forking, Merging, and Tagging &mdash; Branching,</a></li>
<li><a href="delta_format.wiki">Format &mdash; Fossil Delta</a></li>
<li><a href="fileformat.wiki">Format &mdash; Fossil File</a></li>
<li><a href="image-format-vs-repo-size.md">Format vs Fossil Repo Size &mdash; Image</a></li>
<li><a href="../../../md_rules">Formatting Rules &mdash; Markdown</a></li>
<li><a href="../../../wiki_rules">Formatting Rules &mdash; Wiki</a></li>
<li><a href="forum.wiki">Forums &mdash; Fossil</a></li>
<li><a href="blockchain.md"><b>Fossil As Blockchain</b></a></li>
<li><a href="changes.wiki"><b>Fossil Changelog</b></a></li>
<li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li>

<li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li>
<li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li>

<li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li>
<li><a href="forum.wiki"><b>Fossil Forums</b></a></li>
<li><a href="grep.md"><b>Fossil grep vs POSIX grep</b></a></li>
<li><a href="quickstart.wiki"><b>Fossil Quick Start Guide</b></a></li>
<li><a href="selfcheck.wiki"><b>Fossil Repository Integrity Self Checks</b></a></li>
<li><a href="selfhost.wiki"><b>Fossil Self Hosting Repositories</b></a></li>
<li><a href="settings.wiki"><b>Fossil Settings</b></a></li>
<li><a href="hints.wiki"><b>Fossil Tips And Usage Hints</b></a></li>
<li><a href="fossil-v-git.wiki"><b>Fossil Versus Git</b></a></li>
<li><a href="quotes.wiki">Fossil, Git, and DVCSes in General &mdash; Quotes: What People Are Saying About</a></li>
<li><a href="fossil_prompt.wiki"><b>Fossilized Bash Prompt</b></a></li>
<li><a href="faq.wiki"><b>Frequently Asked Questions</b></a></li>
<li><a href="quotes.wiki">General &mdash; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
<li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
<li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>

<li><a href="mirrorlimitations.md">Git Mirrors &mdash; Limitations On</a></li>
<li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
<li><a href="mirrortogithub.md">GitHub &mdash; How To Mirror A Fossil Repository On</a></li>
<li><a href="globs.md">Glob Patterns &mdash; File Name</a></li>
<li><a href="env-opts.md">Global Options &mdash; Environment Variables and</a></li>
<li><a href="customgraph.md">Graph &mdash; Theming: Customizing the Timeline</a></li>
<li><a href="grep.md">grep &mdash; Fossil grep vs POSIX</a></li>
<li><a href="grep.md">grep vs POSIX grep &mdash; Fossil</a></li>

<li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
<li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
<li><a href="hacker-howto.wiki"><b>Hacker How-To</b></a></li>
<li><a href="adding_code.wiki"><b>Hacking Fossil</b></a></li>
<li><a href="rebaseharm.md">Harmful &mdash; Rebase Considered</a></li>
<li><a href="hashpolicy.wiki"><b>Hash Policy: Choosing Between SHA1 and SHA3-256</b></a></li>
<li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>


<li><a href="index.wiki"><b>Home Page</b></a></li>
<li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
<li><a href="aboutcgi.wiki"><b>How CGI Works In Fossil</b></a></li>
<li><a href="aboutdownload.wiki"><b>How The Download Page Works</b></a></li>
<li><a href="server/"><b>How To Configure A Fossil Server</b></a></li>
<li><a href="newrepo.wiki"><b>How To Create A New Fossil Repository</b></a></li>
<li><a href="mirrortogithub.md"><b>How To Mirror A Fossil Repository On GitHub</b></a></li>







>













>













>


















>


>















>








>







>
>







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
<li><a href="contribute.wiki"><b>Contributing Code or Documentation To The Fossil Project</b></a></li>
<li><a href="copyright-release.html"><b>Contributor License Agreement</b></a></li>
<li><a href="whyusefossil.wiki">Control &mdash; Benefits Of Version</a></li>
<li><a href="concepts.wiki">Core Concepts &mdash; Fossil</a></li>
<li><a href="newrepo.wiki">Create A New Fossil Repository &mdash; How To</a></li>
<li><a href="private.wiki"><b>Creating, Syncing, and Deleting Private Branches</b></a></li>
<li><a href="qandc.wiki">Criticisms &mdash; Questions And</a></li>
<li><a href="css-tricks.md">CSS Tips and Tricks &mdash; Fossil</a></li>
<li><a href="customskin.md"><b>Custom Skins</b></a></li>
<li><a href="customskin.md">Customizing The Appearance of Web Pages &mdash; Theming:</a></li>
<li><a href="custom_ticket.wiki"><b>Customizing The Ticket System</b></a></li>
<li><a href="customgraph.md">Customizing the Timeline Graph &mdash; Theming:</a></li>
<li><a href="tech_overview.wiki">Databases Used By Fossil &mdash; SQLite</a></li>
<li><a href="defcsp.md">Default Content Security Policy &mdash; The</a></li>
<li><a href="antibot.wiki"><b>Defense against Spiders and Bots</b></a></li>
<li><a href="shunning.wiki">Deleting Content From Fossil &mdash; Shunning:</a></li>
<li><a href="private.wiki">Deleting Private Branches &mdash; Creating, Syncing, and</a></li>
<li><a href="delta_encoder_algorithm.wiki">Delta Encoding Algorithm &mdash; Fossil</a></li>
<li><a href="delta_format.wiki">Delta Format &mdash; Fossil</a></li>
<li><a href="tech_overview.wiki">Design And Implementation Of Fossil &mdash; A Technical Overview Of The</a></li>
<li><a href="theory1.wiki">Design Of The Fossil DVCS &mdash; Thoughts On The</a></li>
<li><a href="hacker-howto.wiki">Developers Guide &mdash; Fossil</a></li>
<li><a href="caps/admin-v-setup.md"><b>Differences Between Setup and Admin Users</b></a></li>
<li><a href="embeddeddoc.wiki">Documentation &mdash; Embedded Project</a></li>
<li><a href="contribute.wiki">Documentation To The Fossil Project &mdash; Contributing Code or</a></li>
<li><a href="aboutdownload.wiki">Download Page Works &mdash; How The</a></li>
<li><a href="theory1.wiki">DVCS &mdash; Thoughts On The Design Of The Fossil</a></li>
<li><a href="quotes.wiki">DVCSes in General &mdash; Quotes: What People Are Saying About Fossil, Git, and</a></li>
<li><a href="alerts.md"><b>Email Alerts And Notifications</b></a></li>
<li><a href="embeddeddoc.wiki"><b>Embedded Project Documentation</b></a></li>
<li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &mdash; Fossil Delta</a></li>
<li><a href="encryptedrepos.wiki">Encrypted Repositories &mdash; How To Use</a></li>
<li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li>
<li><a href="event.wiki"><b>Events</b></a></li>
<li><a href="webpage-ex.md">Examples &mdash; Webpage</a></li>
<li><a href="gitusers.md">Experience &mdash; Hints For Users With Git</a></li>
<li><a href="inout.wiki">Export To And From Git &mdash; Import And</a></li>
<li><a href="fossil-from-msvc.wiki">Express 2010 IDE &mdash; Integrating Fossil in the Microsoft</a></li>
<li><a href="serverext.wiki">Extensions &mdash; CGI Server</a></li>
<li><a href="serverext.wiki">Extensions To A Fossil Server Using CGI Scripts &mdash; Adding</a></li>
<li><a href="adding_code.wiki">Features To Fossil &mdash; Adding New</a></li>
<li><a href="fileformat.wiki">File Format &mdash; Fossil</a></li>
<li><a href="globs.md"><b>File Name Glob Patterns</b></a></li>
<li><a href="unvers.wiki">Files &mdash; Unversioned</a></li>
<li><a href="branching.wiki">Forking, Merging, and Tagging &mdash; Branching,</a></li>
<li><a href="delta_format.wiki">Format &mdash; Fossil Delta</a></li>
<li><a href="fileformat.wiki">Format &mdash; Fossil File</a></li>
<li><a href="image-format-vs-repo-size.md">Format vs Fossil Repo Size &mdash; Image</a></li>
<li><a href="../../../md_rules">Formatting Rules &mdash; Markdown</a></li>
<li><a href="../../../wiki_rules">Formatting Rules &mdash; Wiki</a></li>
<li><a href="forum.wiki">Forums &mdash; Fossil</a></li>
<li><a href="blockchain.md"><b>Fossil As Blockchain</b></a></li>
<li><a href="changes.wiki"><b>Fossil Changelog</b></a></li>
<li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li>
<li><a href="css-tricks.md"><b>Fossil CSS Tips and Tricks</b></a></li>
<li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li>
<li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li>
<li><a href="hacker-howto.wiki"><b>Fossil Developers Guide</b></a></li>
<li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li>
<li><a href="forum.wiki"><b>Fossil Forums</b></a></li>
<li><a href="grep.md"><b>Fossil grep vs POSIX grep</b></a></li>
<li><a href="quickstart.wiki"><b>Fossil Quick Start Guide</b></a></li>
<li><a href="selfcheck.wiki"><b>Fossil Repository Integrity Self Checks</b></a></li>
<li><a href="selfhost.wiki"><b>Fossil Self Hosting Repositories</b></a></li>
<li><a href="settings.wiki"><b>Fossil Settings</b></a></li>
<li><a href="hints.wiki"><b>Fossil Tips And Usage Hints</b></a></li>
<li><a href="fossil-v-git.wiki"><b>Fossil Versus Git</b></a></li>
<li><a href="quotes.wiki">Fossil, Git, and DVCSes in General &mdash; Quotes: What People Are Saying About</a></li>
<li><a href="fossil_prompt.wiki"><b>Fossilized Bash Prompt</b></a></li>
<li><a href="faq.wiki"><b>Frequently Asked Questions</b></a></li>
<li><a href="quotes.wiki">General &mdash; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
<li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
<li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
<li><a href="gitusers.md">Git Experience &mdash; Hints For Users With</a></li>
<li><a href="mirrorlimitations.md">Git Mirrors &mdash; Limitations On</a></li>
<li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
<li><a href="mirrortogithub.md">GitHub &mdash; How To Mirror A Fossil Repository On</a></li>
<li><a href="globs.md">Glob Patterns &mdash; File Name</a></li>
<li><a href="env-opts.md">Global Options &mdash; Environment Variables and</a></li>
<li><a href="customgraph.md">Graph &mdash; Theming: Customizing the Timeline</a></li>
<li><a href="grep.md">grep &mdash; Fossil grep vs POSIX</a></li>
<li><a href="grep.md">grep vs POSIX grep &mdash; Fossil</a></li>
<li><a href="hacker-howto.wiki">Guide &mdash; Fossil Developers</a></li>
<li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
<li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
<li><a href="hacker-howto.wiki"><b>Hacker How-To</b></a></li>
<li><a href="adding_code.wiki"><b>Hacking Fossil</b></a></li>
<li><a href="rebaseharm.md">Harmful &mdash; Rebase Considered</a></li>
<li><a href="hashpolicy.wiki"><b>Hash Policy: Choosing Between SHA1 and SHA3-256</b></a></li>
<li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
<li><a href="gitusers.md"><b>Hints For Users With Git Experience</b></a></li>
<li><a href="history.md">History Of Fossil &mdash; The Purpose And</a></li>
<li><a href="index.wiki"><b>Home Page</b></a></li>
<li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
<li><a href="aboutcgi.wiki"><b>How CGI Works In Fossil</b></a></li>
<li><a href="aboutdownload.wiki"><b>How The Download Page Works</b></a></li>
<li><a href="server/"><b>How To Configure A Fossil Server</b></a></li>
<li><a href="newrepo.wiki"><b>How To Create A New Fossil Repository</b></a></li>
<li><a href="mirrortogithub.md"><b>How To Mirror A Fossil Repository On GitHub</b></a></li>
214
215
216
217
218
219
220

221
222
223
224
225
226
227
<li><a href="contribute.wiki">Project &mdash; Contributing Code or Documentation To The Fossil</a></li>
<li><a href="embeddeddoc.wiki">Project Documentation &mdash; Embedded</a></li>
<li><a href="foss-cklist.wiki">Projects &mdash; Checklist For Successful Open-Source</a></li>
<li><a href="childprojects.wiki">Projects &mdash; Child</a></li>
<li><a href="fossil_prompt.wiki">Prompt &mdash; Fossilized Bash</a></li>
<li><a href="sync.wiki">Protocol &mdash; The Fossil Sync</a></li>
<li><a href="tls-nginx.md"><b>Proxying Fossil via HTTPS with nginx</b></a></li>

<li><a href="faq.wiki">Questions &mdash; Frequently Asked</a></li>
<li><a href="qandc.wiki"><b>Questions And Criticisms</b></a></li>
<li><a href="quickstart.wiki">Quick Start Guide &mdash; Fossil</a></li>
<li><a href="quotes.wiki"><b>Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</b></a></li>
<li><a href="rebaseharm.md"><b>Rebase Considered Harmful</b></a></li>
<li><a href="caps/ref.html">Reference &mdash; User Capability</a></li>
<li><a href="image-format-vs-repo-size.md">Repo Size &mdash; Image Format vs Fossil</a></li>







>







224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
<li><a href="contribute.wiki">Project &mdash; Contributing Code or Documentation To The Fossil</a></li>
<li><a href="embeddeddoc.wiki">Project Documentation &mdash; Embedded</a></li>
<li><a href="foss-cklist.wiki">Projects &mdash; Checklist For Successful Open-Source</a></li>
<li><a href="childprojects.wiki">Projects &mdash; Child</a></li>
<li><a href="fossil_prompt.wiki">Prompt &mdash; Fossilized Bash</a></li>
<li><a href="sync.wiki">Protocol &mdash; The Fossil Sync</a></li>
<li><a href="tls-nginx.md"><b>Proxying Fossil via HTTPS with nginx</b></a></li>
<li><a href="history.md">Purpose And History Of Fossil &mdash; The</a></li>
<li><a href="faq.wiki">Questions &mdash; Frequently Asked</a></li>
<li><a href="qandc.wiki"><b>Questions And Criticisms</b></a></li>
<li><a href="quickstart.wiki">Quick Start Guide &mdash; Fossil</a></li>
<li><a href="quotes.wiki"><b>Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</b></a></li>
<li><a href="rebaseharm.md"><b>Rebase Considered Harmful</b></a></li>
<li><a href="caps/ref.html">Reference &mdash; User Capability</a></li>
<li><a href="image-format-vs-repo-size.md">Repo Size &mdash; Image Format vs Fossil</a></li>
272
273
274
275
276
277
278

279
280
281
282
283
284
285

286
287

288
289
290
291
292
293
294
295

296
297
298
299
300
301
302
<li><a href="backoffice.md"><b>The "Backoffice" mechanism of Fossil</b></a></li>
<li><a href="blame.wiki"><b>The Annotate/Blame Algorithm Of Fossil</b></a></li>
<li><a href="defcsp.md"><b>The Default Content Security Policy</b></a></li>
<li><a href="makefile.wiki"><b>The Fossil Build Process</b></a></li>
<li><a href="sync.wiki"><b>The Fossil Sync Protocol</b></a></li>
<li><a href="tickets.wiki"><b>The Fossil Ticket System</b></a></li>
<li><a href="webui.wiki"><b>The Fossil Web Interface</b></a></li>

<li><a href="th1.md"><b>The TH1 Scripting Language</b></a></li>
<li><a href="customskin.md"><b>Theming: Customizing The Appearance of Web Pages</b></a></li>
<li><a href="customgraph.md"><b>Theming: Customizing the Timeline Graph</b></a></li>
<li><a href="theory1.wiki"><b>Thoughts On The Design Of The Fossil DVCS</b></a></li>
<li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
<li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
<li><a href="customgraph.md">Timeline Graph &mdash; Theming: Customizing the</a></li>

<li><a href="hints.wiki">Tips And Usage Hints &mdash; Fossil</a></li>
<li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>

<li><a href="unvers.wiki"><b>Unversioned Files</b></a></li>
<li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li>
<li><a href="hints.wiki">Usage Hints &mdash; Fossil Tips And</a></li>
<li><a href="javascript.md"><b>Use of JavaScript in Fossil</b></a></li>
<li><a href="fiveminutes.wiki">User &mdash; Up and Running in 5 Minutes as a Single</a></li>
<li><a href="caps/">User Capabilities &mdash; Administering</a></li>
<li><a href="caps/ref.html"><b>User Capability Reference</b></a></li>
<li><a href="caps/admin-v-setup.md">Users &mdash; Differences Between Setup and Admin</a></li>

<li><a href="serverext.wiki">Using CGI Scripts &mdash; Adding Extensions To A Fossil Server</a></li>
<li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li>
<li><a href="env-opts.md">Variables and Global Options &mdash; Environment</a></li>
<li><a href="whyusefossil.wiki">Version Control &mdash; Benefits Of</a></li>
<li><a href="checkin_names.wiki">Version Names &mdash; Check-in And</a></li>
<li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
<li><a href="tls-nginx.md">via HTTPS with nginx &mdash; Proxying Fossil</a></li>







>







>


>








>







283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
<li><a href="backoffice.md"><b>The "Backoffice" mechanism of Fossil</b></a></li>
<li><a href="blame.wiki"><b>The Annotate/Blame Algorithm Of Fossil</b></a></li>
<li><a href="defcsp.md"><b>The Default Content Security Policy</b></a></li>
<li><a href="makefile.wiki"><b>The Fossil Build Process</b></a></li>
<li><a href="sync.wiki"><b>The Fossil Sync Protocol</b></a></li>
<li><a href="tickets.wiki"><b>The Fossil Ticket System</b></a></li>
<li><a href="webui.wiki"><b>The Fossil Web Interface</b></a></li>
<li><a href="history.md"><b>The Purpose And History Of Fossil</b></a></li>
<li><a href="th1.md"><b>The TH1 Scripting Language</b></a></li>
<li><a href="customskin.md"><b>Theming: Customizing The Appearance of Web Pages</b></a></li>
<li><a href="customgraph.md"><b>Theming: Customizing the Timeline Graph</b></a></li>
<li><a href="theory1.wiki"><b>Thoughts On The Design Of The Fossil DVCS</b></a></li>
<li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
<li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
<li><a href="customgraph.md">Timeline Graph &mdash; Theming: Customizing the</a></li>
<li><a href="css-tricks.md">Tips and Tricks &mdash; Fossil CSS</a></li>
<li><a href="hints.wiki">Tips And Usage Hints &mdash; Fossil</a></li>
<li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
<li><a href="css-tricks.md">Tricks &mdash; Fossil CSS Tips and</a></li>
<li><a href="unvers.wiki"><b>Unversioned Files</b></a></li>
<li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li>
<li><a href="hints.wiki">Usage Hints &mdash; Fossil Tips And</a></li>
<li><a href="javascript.md"><b>Use of JavaScript in Fossil</b></a></li>
<li><a href="fiveminutes.wiki">User &mdash; Up and Running in 5 Minutes as a Single</a></li>
<li><a href="caps/">User Capabilities &mdash; Administering</a></li>
<li><a href="caps/ref.html"><b>User Capability Reference</b></a></li>
<li><a href="caps/admin-v-setup.md">Users &mdash; Differences Between Setup and Admin</a></li>
<li><a href="gitusers.md">Users With Git Experience &mdash; Hints For</a></li>
<li><a href="serverext.wiki">Using CGI Scripts &mdash; Adding Extensions To A Fossil Server</a></li>
<li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li>
<li><a href="env-opts.md">Variables and Global Options &mdash; Environment</a></li>
<li><a href="whyusefossil.wiki">Version Control &mdash; Benefits Of</a></li>
<li><a href="checkin_names.wiki">Version Names &mdash; Check-in And</a></li>
<li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
<li><a href="tls-nginx.md">via HTTPS with nginx &mdash; Proxying Fossil</a></li>
Changes to www/private.wiki.
29
30
31
32
33
34
35
36
37
38
39














40
41
42
43
44
45
46

<blockquote><pre>
fossil update trunk
fossil merge private
fossil commit
</pre></blockquote>

The private branch remains private.  (There is no way to convert a private
branch into a public branch.)  But all of the changes associated with
the private branch are now folded into the public branch and are hence
visible to other users of the project.















<h2>Syncing Private Branches</h2>

A private branch normally stays on the one repository where it was
originally created.  But sometimes you want to share private branches
with another repository.  For example, you might be building a cross-platform
application and have separate repositories on your Windows laptop,







<
|


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







29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

<blockquote><pre>
fossil update trunk
fossil merge private
fossil commit
</pre></blockquote>


The private branch remains private, but all of the changes associated with
the private branch are now folded into the public branch and are hence
visible to other users of the project.

A private branch created with Fossil version 1.30 or newer can also be
converted into a public branch using the <code>fossil publish</code>
command.  However, there is no way to convert a private branch created with
older versions of Fossil into a public branch.

The <code>--integrate</code> option of <code>fossil merge</code> (to close
the merged branch when committing) is ignored for a private branch -- or the
check-in manifest of the resulting merge child would include a
<code>+close</code> tag referring to the leaf check-in on the private branch,
and generate a missing artifact reference on repository clones without that
private branch.  It's still possible to close the leaf of the private branch
(after committing the merge child) with the <code>fossil amend --close</code>
command.

<h2>Syncing Private Branches</h2>

A private branch normally stays on the one repository where it was
originally created.  But sometimes you want to share private branches
with another repository.  For example, you might be building a cross-platform
application and have separate repositories on your Windows laptop,
Changes to www/qandc.wiki.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<title>Questions And Criticisms</title>
<nowiki>
<h1 align="center">Questions And Criticisms</h1>

<p>This page is a collection of real questions and criticisms that have been
raised against fossil together with responses from the program's author.</p>

<p>Note: See also the <a href="faq.wiki">Frequently Asked Questions</a>.</p>

<b>Fossil sounds like a lot of reinvention of the wheel.
Why create your own DVCS when you could have reused mercurial?</b>

<blockquote>
  <p>I wrote fossil because none of the
  other available DVCSes met my needs.  If the other DVCSes do




|
|
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<title>Questions And Criticisms</title>
<nowiki>
<h1 align="center">Questions And Criticisms</h1>

<p>This page is a collection of real questions and criticisms that were
raised against Fossil early in its history (circa 2008).
This page is old and has not been kept up-to-date.  See the
</nowiki>[/finfo?name=www/qandc.wiki|change history of this page]<nowiki>.</p>

<b>Fossil sounds like a lot of reinvention of the wheel.
Why create your own DVCS when you could have reused mercurial?</b>

<blockquote>
  <p>I wrote fossil because none of the
  other available DVCSes met my needs.  If the other DVCSes do
Changes to www/quickstart.wiki.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<title>Fossil Quick Start Guide</title>
<h1 align="center">Fossil Quick Start</h1>

<p>This is a guide to get you started using fossil quickly
and painlessly.</p>

<h2 id="install">Installing</h2>

    <p>Fossil is a single self-contained C program.  You need to
    either download a
    <a href="https://www.fossil-scm.org/fossil/uv/download.html">precompiled
    binary</a>
    or <a href="build.wiki">compile it yourself</a> from sources.
    Install fossil by putting the fossil binary
    someplace on your $PATH.</p>

<a name="fslclone"></a>
<h2>General Work Flow</h2>

    <p>Fossil works with repository files (a database with the project's
    complete history) and with checked-out local trees (the working directory



|









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<title>Fossil Quick Start Guide</title>
<h1 align="center">Fossil Quick Start</h1>

<p>This is a guide to help you get started using Fossil quickly
and painlessly.</p>

<h2 id="install">Installing</h2>

    <p>Fossil is a single self-contained C program.  You need to
    either download a
    <a href="https://www.fossil-scm.org/fossil/uv/download.html">precompiled
    binary</a>
    or <a href="build.wiki">compile it yourself</a> from sources.
    Install Fossil by putting the fossil binary
    someplace on your $PATH.</p>

<a name="fslclone"></a>
<h2>General Work Flow</h2>

    <p>Fossil works with repository files (a database with the project's
    complete history) and with checked-out local trees (the working directory
389
390
391
392
393
394
395
396
397
398




399
400
401
402
403
    is easily done on the command-line.  For example, to sync with
    a co-workers repository on your LAN, you might type:</p>

    <blockquote>
    <b>fossil sync http://192.168.1.36:8080/ --proxy off</b>
    </blockquote>

<h2>More Hints</h2>

    <p>A [/help | complete list of commands] is available, as is the




    [./hints.wiki|helpful hints] document.  See the
    [./permutedindex.html#pindex|permuted index] for additional
    documentation.

    <p>Explore and have fun!</p>







|

|
>
>
>
>
|
|
<
|
<
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404

405

    is easily done on the command-line.  For example, to sync with
    a co-workers repository on your LAN, you might type:</p>

    <blockquote>
    <b>fossil sync http://192.168.1.36:8080/ --proxy off</b>
    </blockquote>

<h2 id="links">Other Resources</h2>

   <ul>
   <li> <a href="./gitusers.md">Hints for users with prior Git experience</a>
   <li> <a href="./whyusefossil.wiki">Benefits Of Version Control</a>
   <li> <a href="./history.md">The Purpose And History of Fossil</a>
   <li> <a href="./branching.wiki">Branching, Forking, Merge, and Taggings</a>
   <li> <a href="./hints.wiki">Tips and Usage Hints</a>
   <li> <a href="./permutedindex.html">Comprehensive documentation index</a>

   </ul>

Changes to www/rebaseharm.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Rebase Considered Harmful

Fossil deliberately omits a "rebase" command, because the original
designer of Fossil (and [original author][vhist] of this article) considers rebase to be 
an anti-pattern to be avoided. This article attempts to
explain that point of view.

[vhist]: /finfo?name=www/rebaseharm.md&ubg

## 1.0 Rebasing is dangerous

Most people, even strident advocates of rebase, agree that rebase can
cause problems when misused. The Git rebase documentation talks about the
[golden rule of rebase][golden]: that it should never be used on a public
branch.  Horror stories of misused rebase abound, and the rebase 
documentation devotes considerable space toward explaining how to
recover from rebase errors and/or misuse.

## <a name="cap-loss"></a>2.0 Rebase provides no new capabilities

Sometimes sharp and dangerous tools are justified,


|










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Rebase Considered Harmful

Fossil deliberately omits a "rebase" command because the original
designer of Fossil (and [original author][vhist] of this article) considers rebase to be 
an anti-pattern to be avoided. This article attempts to
explain that point of view.

[vhist]: /finfo?name=www/rebaseharm.md&ubg

## 1.0 Rebasing is dangerous

Most people, even strident advocates of rebase, agree that rebase can
cause problems when misused. The Git rebase documentation talks about the
[golden rule of rebasing][golden]: never rebase on a public
branch.  Horror stories of misused rebase abound, and the rebase 
documentation devotes considerable space toward explaining how to
recover from rebase errors and/or misuse.

## <a name="cap-loss"></a>2.0 Rebase provides no new capabilities

Sometimes sharp and dangerous tools are justified,
55
56
57
58
59
60
61



62
63
64
65
66
67
68
69
70
71
72
73
74
75

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
desirable and edifying, but retain the option to show the real,
complete, messy history for cases where detail and accuracy are more
important.

So, another way of thinking about rebase is that it is a kind of
merge that intentionally forgets some details in order to
not overwhelm the weak history display mechanisms available in Git.




### <a name="clean-diffs"></a>2.2 Rebase does not actually provide better feature-branch diffs

Another argument, often cited, is that rebasing a feature branch
allows one to see just the changes in the feature branch without
the concurrent changes in the main line of development. 
Consider a hypothetical case:

![unmerged feature branch](./rebase03.svg)

In the above, a feature branch consisting of check-ins C3 and C5 is
run concurrently with the main line in check-ins C4 and C6.  Advocates
for rebase say that you should rebase the feature branch to the tip
of main like the following:


![rebased feature branch](./rebase04.svg)

You could choose to collapse C3\' and C5\' into a single check-in
as part of this rebase, but thats a side issue well deal with
[separately](#collapsing).

If only merge is available, one would do a merge from the concurrent
mainline changes into the feature branch as follows:

![merged feature branch](./rebase05.svg)

Check-ins C5\' and C7 check-ins hold identical code.  The only
difference is in their history.  

The argument from rebase advocates
is that with merge it is difficult to see only the changes associated
with the feature branch without the commingled mainline changes.
In other words, diff(C2,C7) shows changes associated both the feature
branch and from the mainline, whereas in the rebase case
diff(C6,C5\') should only the feature branch changes.

But that argument is comparing apples to oranges, since the two diffs
do not have the same baseline.  The correct way to see only the feature
branch changes in the merge case is not diff(C2,C7) but rather diff(C6,C7).

<center><table border="1" cellpadding="5" cellspacing="0">
<tr><th>Rebase<th>Merge<th>What You See







>
>
>













|
>




|


|
|









|

|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
desirable and edifying, but retain the option to show the real,
complete, messy history for cases where detail and accuracy are more
important.

So, another way of thinking about rebase is that it is a kind of
merge that intentionally forgets some details in order to
not overwhelm the weak history display mechanisms available in Git.
Wouldn't it be better, less error-prone, and easier on users
to enhance the history display mechanisms in Git so that rebasing 
for a clean, linear history became unnecessary?

### <a name="clean-diffs"></a>2.2 Rebase does not actually provide better feature-branch diffs

Another argument, often cited, is that rebasing a feature branch
allows one to see just the changes in the feature branch without
the concurrent changes in the main line of development. 
Consider a hypothetical case:

![unmerged feature branch](./rebase03.svg)

In the above, a feature branch consisting of check-ins C3 and C5 is
run concurrently with the main line in check-ins C4 and C6.  Advocates
for rebase say that you should rebase the feature branch to the tip
of main in order to remove main-line development differences from
the feature branch's history:

![rebased feature branch](./rebase04.svg)

You could choose to collapse C3\' and C5\' into a single check-in
as part of this rebase, but that's a side issue we'll deal with
[separately](#collapsing).

Because Fossil purposefully lacks rebase, the closest you can get to this same check-in
history is the following merge:

![merged feature branch](./rebase05.svg)

Check-ins C5\' and C7 check-ins hold identical code.  The only
difference is in their history.  

The argument from rebase advocates
is that with merge it is difficult to see only the changes associated
with the feature branch without the commingled mainline changes.
In other words, diff(C2,C7) shows changes from both the feature
branch and from the mainline, whereas in the rebase case
diff(C6,C5\') shows only the feature branch changes.

But that argument is comparing apples to oranges, since the two diffs
do not have the same baseline.  The correct way to see only the feature
branch changes in the merge case is not diff(C2,C7) but rather diff(C6,C7).

<center><table border="1" cellpadding="5" cellspacing="0">
<tr><th>Rebase<th>Merge<th>What You See
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

206



207

208

209
210
211
212







213
214

215
216
217


218
219
220

221
222
223

224


225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340

So, to help with the problem of viewing changes associated with a feature
branch, perhaps what is needed is not rebase but rather better tools to 
help users identify an appropriate baseline for their diffs.

## <a name="siloing"></a>3.0 Rebase encourages siloed development

The [golden rule of rebase][golden] is that you should never do it
on public branches, so if you are using rebase as intended, that means
you are keeping private branches.  Or, to put it another way, you are
doing siloed development.  You are not sharing your intermediate work
with collaborators.  This is not good for product quality.

[Nagappan, et. al][nagappan] studied bugs in Windows Vista and found
that best predictor of bugs is the distance on the org-chart between
the stake-holders.  Or, bugs are reduced when the engineers talk to

one another.  Similar findings arise in other disciplines.  Keeping
private branches does not prove that developers are communicating
insufficiently, but it is a key symptom that problem.

[Weinberg][weinberg] argues programming should be "egoless."  That
is to say, programmers should avoid linking their code with their sense of
self, as that makes it more difficult for them to find and respond
to bugs, and hence makes them less productive.  Many developers are
drawn to private branches out of sense of ego.  "I want to get the
code right before I publish it."  I sympathize with this sentiment,
and am frequently guilty of it myself.  It is humbling to display
your stupid mistake to the whole world on an internet that
never forgets.  And yet, humble programmers generate better code.

What is the fastest path to solid code? Is it to continue staring at
your private branch to seek out every last bug, or is it to publish it
as-is, whereupon the many eyeballs will immediately see that last stupid
error in the code? Testing and development are often done by separate
groups within a larger software development organization, because
developers get too close to their own code to see every problem in it.

Given that, is it better for those many eyeballs to find your problems
while theyre still isolated on a feature branch, or should that vetting
wait until you finally push a collapsed version of a private working
branch to the parent repo? Will the many eyeballs even see those errors
when they’re intermingled with code implementing some tasty new feature?

## <a name="testing"></a>4.0 Rebase commits untested check-ins to the blockchain

Rebase adds new check-ins to the blockchain without giving the operator
an opportunity to test and verify those check-ins.  Just because the
underlying three-way merge had no conflict does not mean that the resulting
code actually works.  Thus, rebase runs the very real risk of adding
non-functional check-ins to the permanent record.

Of course, a user can also commit untested or broken check-ins without
the help of rebase.  But at least with an ordinary commit or merge
(in Fossil at least), the operator
has the *opportunity* to test and verify the merge before it is committed,
and a chance to back out or fix the change if it is broken, without leaving
busted check-ins on the blockchain to complicate future bisects.

With rebase, pre-commit testing is not an option.

## <a name="timestamps"></a>5.0 Rebase causes timestamp confusion

Consider the earlier example of rebasing a feature branch:

![rebased feature branch, again](./rebase04.svg)

What timestamps go on the C3\' and C5\' check-ins?  If you choose
the same timestamps as the original C3 and C5, then you have the
odd situation C3' is older than its parent C6.  We call that a
"timewarp" in Fossil.  Timewarps can also happen due to misconfigured
system clocks, so they are not unique to rebase.  But they are very
confusing and best avoided.  The other option is to provide new
unique timestamps for C3' and C5'.  But then you lose the information
about when those check-ins were originally created, which can make
historical analysis of changes more difficult, and might also
complicate prior art claims.

## <a name="lying"></a>6.0 Rebasing is the same as lying

By discarding parentage information, rebase attempts to deceive the
reader about how the code actually came together.

The [Git rebase documentation][gitrebase] admits as much.  They acknowledge
that when you view a repository as record of what actually happened,
doing a rebase is "blasphemous" and "you're _lying_ about what
actually happened", but then goes on to justify rebase as follows:

>
_"The opposing point of view is that the commit history is the **story of 
how your project was made.** You wouldn\'t publish the first draft of a 
book, and the manual for how to maintain your software deserves careful
editing. This is the camp that uses tools like rebase and filter-branch 
to tell the story in the way thats best for future readers."_

I reject this argument utterly.

Unless your project is a work of fiction, it is not a "story" but a "history."



Honorable writers adjust their narrative to fit

history.  Rebase adjusts history to fit the narrative.


Truthful texts can be redrafted for clarity and accuracy.
Fossil supports this by providing mechanisms to fix
typos in check-in comments, attach supplemental notes,







and make other editorial changes.
The corrections are accomplished by adding

new modification records to the blockchain.  The original incorrect
inputs are preserved in the blockchain and are easily accessible.
But for routine display purposes, the more readable edited


presentation is provided.  A repository can be a true and accurate
representation of history even without getting everything perfect
on the first draft.


Unfortunately, Git does not provide the ability to add corrections
or clarifications to historical check-ins in its blockchain.  Hence,

once again, rebase can be seen as an attempt to work around limitations


of Git.  Wouldn't it be better to fix the tool rather than to lie about
the project history?

## <a name="collapsing"></a>7.0 Collapsing check-ins throws away valuable information

One of the oft-cited advantages of rebasing in Git is that it lets you
collapse multiple check-ins down to a single check-in to make the
development history “clean.” The intent is that development appear as
though every feature were created in a single step: no multi-step
evolution, no back-tracking, no false starts, no mistakes. This ignores
actual developer psychology: ideas rarely spring forth from fingers to
files in faultless finished form. A wish for collapsed, finalized
check-ins is a wish for a counterfactual situation.

The common counterargument is that collapsed check-ins represent a
better world, the ideal were striving for. What that argument overlooks
is that we must throw away valuable information to get there.

### <a name="empathy"></a>7.1 Individual check-ins support developer empathy

Ideally, future developers of our software can understand every feature
in it using only context available in the version of the code they start
work with. Prior to widespread version control, developers had no choice
but to work that way.  Pre-existing codebases could only be understood
as-is or not at all.  Developers in that world had an incentive to
develop software that was easy to understand retrospectively, even if
they were selfish people, because they knew they might end up being
those future developers!

Yet, sometimes we come upon a piece of code that we simply cannot
understand. If you have never asked yourself, What was this codes
developer thinking? you havent been developing software for very long.

When a developer can go back to the individual check-ins leading up to
the current code, they can work out the answers to such questions using
only the level of empathy necessary to be a good developer. To
understand such code using only the finished form, you are asking future
developers to make intuitive leaps that the original developer was
unable to make. In other words, you are asking your future maintenance
developers to be smarter than the original developers!  Thats a
beautiful wish, but theres a sharp limit to how far you can carry it.
Eventually you hit the limits of human brilliance.

When the operation of some bit of code is not obvious, both Fossil and
Git let you run a [`blame`](/help?cmd=blame) on the code file to get
information about each line of code, and from that which check-in last
touched a given line of code. If you squash the check-ins on a branch
down to a single check-in, you throw away the information leading up to
that finished form. Fossil not only preserves the check-ins surrounding
the one that included the line of code youre trying to understand, its
[superior data model][sdm] lets you see the surrounding check-ins in
both directions; not only what lead up to it, but what came next. Git
cant do that short of crawling the block-chain backwards from the tip
of the branch to the check-in you’re looking at, an expensive operation.

We believe it is easier to understand a line of code from the 10-line
check-in it was a part of — and then to understand the surrounding
check-ins as necessary — than it is to understand a 500-line check-in
that collapses a whole branchs worth of changes down to a single
finished feature.

[sdm]: ./fossil-v-git.wiki#durable

### <a name="bisecting"></a>7.2 Bisecting works better on small check-ins

Git lets a developer write a feature in ten check-ins but collapse it
down to an eleventh check-in and then deliberately push only that final
collapsed check-in to the parent repo. Someone else may then do a bisect
that blames the merged check-in as the source of the problem they’re
chasing down; they then have to manually work out which of the 10 steps
the original developer took to create it to find the source of the
actual problem.

Fossil pushes all 11 check-ins to the parent repository by default, so

that someone doing that bisect sees the complete check-in history, so
the bisect will point them at the single original check-in that caused
the problem.

### <a name="comments"></a>7.3 Multiple check-ins require multiple check-in comments

The more comments you have from a given developer on a given body of
code, the more concise documentation you have of that developers
thought process. To resume the bisecting example, a developer trying to
work out what the original developer was thinking with a given change
will have more success given a check-in comment that explains what the
one check-in out of ten blamed by the bisect command was trying to
accomplish than if they must work that out from the eleventh check-ins
comment, which only explains the clean version of the collapsed
feature.

### <a name="cherrypicking"></a>7.4 Cherry-picks work better with small check-ins

While working on a new feature in one branch, you may come across a bug
in the pre-existing code that you need to fix in order for work on that
feature to proceed. You could choose to switch briefly back to the
parent branch, develop the fix there, check it in, then merge the parent
back up to the feature branch in order to continue work, but thats
distracting. If the fix isnt for a critical bug, fixing it on the
parent branch can wait, so its better to maintain your mental working
state by fixing the problem in place on the feature branch, then check
the fix in on the feature branch, resume work on the feature, and later
merge that fix down into the parent branch along with the feature.

But now what happens if another branch *also* needs that fix? Let us say
our code repository has a branch for the current stable release, a
development branch for the next major version, and feature branches off
of the development branch. If we rebase each feature branch down into
the development branch as a single check-in, pushing only the rebase
check-in up to the parent repo, only that fixs developer has the
information locally to perform the cherry-pick of the fix onto the
stable branch.

Developers working on new features often do not care about old stable
versions, yet that stable version may have an end user community that
depends on that version, who either cannot wait for the next stable
version or who wish to put off upgrading to it for some time. Such users







|







|
>
|










|










|


|













|














|
|
|

|
|

|











|


|

|
>
|
>
>
>
|
>
|
>

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

|
>

|
|
>
|
>
>
|
|













|














|
|







|
|








|


|





|














|
>
|
|
<




|



|
|
|








|
|
|









|







115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364

So, to help with the problem of viewing changes associated with a feature
branch, perhaps what is needed is not rebase but rather better tools to 
help users identify an appropriate baseline for their diffs.

## <a name="siloing"></a>3.0 Rebase encourages siloed development

The [golden rule of rebasing][golden] is that you should never do it
on public branches, so if you are using rebase as intended, that means
you are keeping private branches.  Or, to put it another way, you are
doing siloed development.  You are not sharing your intermediate work
with collaborators.  This is not good for product quality.

[Nagappan, et. al][nagappan] studied bugs in Windows Vista and found
that best predictor of bugs is the distance on the org-chart between
the stake-holders. The bug rate is inversely related to the
amount of communication among the engineers.
Similar findings arise in other disciplines.  Keeping
private branches does not prove that developers are communicating
insufficiently, but it is a key symptom that problem.

[Weinberg][weinberg] argues programming should be "egoless."  That
is to say, programmers should avoid linking their code with their sense of
self, as that makes it more difficult for them to find and respond
to bugs, and hence makes them less productive.  Many developers are
drawn to private branches out of sense of ego.  "I want to get the
code right before I publish it."  I sympathize with this sentiment,
and am frequently guilty of it myself.  It is humbling to display
your stupid mistake to the whole world on an Internet that
never forgets.  And yet, humble programmers generate better code.

What is the fastest path to solid code? Is it to continue staring at
your private branch to seek out every last bug, or is it to publish it
as-is, whereupon the many eyeballs will immediately see that last stupid
error in the code? Testing and development are often done by separate
groups within a larger software development organization, because
developers get too close to their own code to see every problem in it.

Given that, is it better for those many eyeballs to find your problems
while they're still isolated on a feature branch, or should that vetting
wait until you finally push a collapsed version of a private working
branch to the parent repo? Will the many eyeballs even see those errors
when they’re intermingled with code implementing some compelling new feature?

## <a name="testing"></a>4.0 Rebase commits untested check-ins to the blockchain

Rebase adds new check-ins to the blockchain without giving the operator
an opportunity to test and verify those check-ins.  Just because the
underlying three-way merge had no conflict does not mean that the resulting
code actually works.  Thus, rebase runs the very real risk of adding
non-functional check-ins to the permanent record.

Of course, a user can also commit untested or broken check-ins without
the help of rebase.  But at least with an ordinary commit or merge
(in Fossil at least), the operator
has the *opportunity* to test and verify the merge before it is committed,
and a chance to back out or fix the change if it is broken without leaving
busted check-ins on the blockchain to complicate future bisects.

With rebase, pre-commit testing is not an option.

## <a name="timestamps"></a>5.0 Rebase causes timestamp confusion

Consider the earlier example of rebasing a feature branch:

![rebased feature branch, again](./rebase04.svg)

What timestamps go on the C3\' and C5\' check-ins?  If you choose
the same timestamps as the original C3 and C5, then you have the
odd situation C3' is older than its parent C6.  We call that a
"timewarp" in Fossil.  Timewarps can also happen due to misconfigured
system clocks, so they are not unique to rebase, but they are very
confusing and so best avoided.  The other option is to provide new
unique timestamps for C3' and C5' but then you lose the information
about when those check-ins were originally created, which can make
historical analysis of changes more difficult. It might also
complicate the legal defense of prior art claims.

## <a name="lying"></a>6.0 Rebasing is lying about the project history

By discarding parentage information, rebase attempts to deceive the
reader about how the code actually came together.

The [Git rebase documentation][gitrebase] admits as much.  They acknowledge
that when you view a repository as record of what actually happened,
doing a rebase is "blasphemous" and "you're _lying_ about what
actually happened", but then goes on to justify rebase as follows:

>
_"The opposing point of view is that the commit history is the **story of 
how your project was made.** You wouldn't publish the first draft of a 
book, and the manual for how to maintain your software deserves careful
editing. This is the camp that uses tools like rebase and filter-branch 
to tell the story in the way that's best for future readers."_

This counter-argument assumes you must
change history in order to enhance readability, which is not true.

In fairness to the Git documentation authors, changing the
project history appears to be the only way to make editorial
changes in Git.
But it does not have to be that way.
Fossil demonstrates how "the story of your project"
can be enhanced without changing the actual history
by allowing users to:


  1.  Edit check-in comments to fix typos or enhance clarity
  2.  Attach supplemental notes to check-ins or whole branches
  3.  Cross-reference check-ins with each other, or with
      wiki, tickets, forum posts, and/or embedded documentation
  4.  Cause mistaken or unused branches to be hidden from
      routine display
  5.  Fix faulty check-in date/times resulting from misconfigured
      system clocks
  6.  And so forth....

These changes are accomplished not by removing or modifying existing
repository entries, but rather by adding new supplemental records.
The original incorrect or unclear inputs are preserved and are
readily accessible.  The original history is preserved.
But for routine display purposes, the more
readable edited presentation is provided.

A repository can be a true and accurate
representation of history even without getting everything perfect
on the first draft.  Those are not contradictory goals, at least
not in theory.

Unfortunately, Git does not currently provide the ability to add
corrections or clarifications or supplimental notes to historical check-ins.
Hence, once again,
rebase can be seen as an attempt to work around limitations
of Git.  Git could be enhanced to support editorial changes
to check-ins. 
Wouldn't it be better to fix the version control tool
rather than requiring users to fabricate a fictitious project history?

## <a name="collapsing"></a>7.0 Collapsing check-ins throws away valuable information

One of the oft-cited advantages of rebasing in Git is that it lets you
collapse multiple check-ins down to a single check-in to make the
development history “clean.” The intent is that development appear as
though every feature were created in a single step: no multi-step
evolution, no back-tracking, no false starts, no mistakes. This ignores
actual developer psychology: ideas rarely spring forth from fingers to
files in faultless finished form. A wish for collapsed, finalized
check-ins is a wish for a counterfactual situation.

The common counterargument is that collapsed check-ins represent a
better world, the ideal we're striving for. What that argument overlooks
is that we must throw away valuable information to get there.

### <a name="empathy"></a>7.1 Individual check-ins support developer empathy

Ideally, future developers of our software can understand every feature
in it using only context available in the version of the code they start
work with. Prior to widespread version control, developers had no choice
but to work that way.  Pre-existing codebases could only be understood
as-is or not at all.  Developers in that world had an incentive to
develop software that was easy to understand retrospectively, even if
they were selfish people, because they knew they might end up being
those future developers!

Yet, sometimes we come upon a piece of code that we simply cannot
understand. If you have never asked yourself, "What was this code's
developer thinking?" you haven't been developing software for very long.

When a developer can go back to the individual check-ins leading up to
the current code, they can work out the answers to such questions using
only the level of empathy necessary to be a good developer. To
understand such code using only the finished form, you are asking future
developers to make intuitive leaps that the original developer was
unable to make. In other words, you are asking your future maintenance
developers to be smarter than the original developers!  That's a
beautiful wish, but there's a sharp limit to how far you can carry it.
Eventually you hit the limits of human brilliance.

When the operation of some bit of code is not obvious, both Fossil and
Git let you run a [`blame`](/help?cmd=blame) on the code file to get
information about each line of code, and from that which check-in last
touched a given line of code. If you squash the check-ins on a branch
down to a single check-in, you throw away the information leading up to
that finished form. Fossil not only preserves the check-ins surrounding
the one that included the line of code you're trying to understand, its
[superior data model][sdm] lets you see the surrounding check-ins in
both directions; not only what lead up to it, but what came next. Git
can't do that short of crawling the block-chain backwards from the tip
of the branch to the check-in you’re looking at, an expensive operation.

We believe it is easier to understand a line of code from the 10-line
check-in it was a part of — and then to understand the surrounding
check-ins as necessary — than it is to understand a 500-line check-in
that collapses a whole branch's worth of changes down to a single
finished feature.

[sdm]: ./fossil-v-git.wiki#durable

### <a name="bisecting"></a>7.2 Bisecting works better on small check-ins

Git lets a developer write a feature in ten check-ins but collapse it
down to an eleventh check-in and then deliberately push only that final
collapsed check-in to the parent repo. Someone else may then do a bisect
that blames the merged check-in as the source of the problem they’re
chasing down; they then have to manually work out which of the 10 steps
the original developer took to create it to find the source of the
actual problem.

An equivalent push in Fossil will send all 11 check-ins to the parent
repository so that a later investigator doing the same sort of bisect
sees the complete check-in history. That bisect will point the
investigator at the single original check-in that caused the problem.


### <a name="comments"></a>7.3 Multiple check-ins require multiple check-in comments

The more comments you have from a given developer on a given body of
code, the more concise documentation you have of that developer's
thought process. To resume the bisecting example, a developer trying to
work out what the original developer was thinking with a given change
will have more success given a check-in comment that explains what the
one check-in out of ten blamed by the "bisect" command was trying to
accomplish than if they must work that out from the eleventh check-in's
comment, which only explains the "clean" version of the collapsed
feature.

### <a name="cherrypicking"></a>7.4 Cherry-picks work better with small check-ins

While working on a new feature in one branch, you may come across a bug
in the pre-existing code that you need to fix in order for work on that
feature to proceed. You could choose to switch briefly back to the
parent branch, develop the fix there, check it in, then merge the parent
back up to the feature branch in order to continue work, but that's
distracting. If the fix isn't for a critical bug, fixing it on the
parent branch can wait, so it's better to maintain your mental working
state by fixing the problem in place on the feature branch, then check
the fix in on the feature branch, resume work on the feature, and later
merge that fix down into the parent branch along with the feature.

But now what happens if another branch *also* needs that fix? Let us say
our code repository has a branch for the current stable release, a
development branch for the next major version, and feature branches off
of the development branch. If we rebase each feature branch down into
the development branch as a single check-in, pushing only the rebase
check-in up to the parent repo, only that fix's developer has the
information locally to perform the cherry-pick of the fix onto the
stable branch.

Developers working on new features often do not care about old stable
versions, yet that stable version may have an end user community that
depends on that version, who either cannot wait for the next stable
version or who wish to put off upgrading to it for some time. Such users
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
any of the individual check-ins that went into that private branch.
Others must either manually disentangle the problematic part of your
merge check-in or back out the entire feature.

## <a name="better-plan"></a>8.0 Cherry-pick merges work better than rebase

Perhaps there are some cases where a rebase-like transformation
is actually helpful.  But those cases are rare.  And when they do
come up, running a series of cherry-pick merges achieve the same
topology, but with advantages:

  1.  Cherry-pick merges preserve an honest record of history.
      (They do in Fossil at least.  Git's file format does not have
      a slot to record cherry-pick merge history, unfortunately.)

  2.  Cherry-picks provide an opportunity to [test each new check-in
      before it is committed][tbc] to the blockchain







|
|
|







386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
any of the individual check-ins that went into that private branch.
Others must either manually disentangle the problematic part of your
merge check-in or back out the entire feature.

## <a name="better-plan"></a>8.0 Cherry-pick merges work better than rebase

Perhaps there are some cases where a rebase-like transformation
is actually helpful, but those cases are rare, and when they do
come up, running a series of cherry-pick merges achieves the same
topology with several advantages:

  1.  Cherry-pick merges preserve an honest record of history.
      (They do in Fossil at least.  Git's file format does not have
      a slot to record cherry-pick merge history, unfortunately.)

  2.  Cherry-picks provide an opportunity to [test each new check-in
      before it is committed][tbc] to the blockchain
Changes to www/server/whyuseaserver.wiki.
40
41
42
43
44
45
46
47
      without needing to actually sync to the device they are using.

  4.  <b>A server provides automatic off-site backups.</b><p>
      A Fossil server is an automatic remote backup for all the work
      going into a project.  You can even set up multiple servers, at
      multiple sites, with automatic synchronization between them, for
      added redundancy.  Such a set up means that no work is lost due
      to a single machine failur







|
40
41
42
43
44
45
46
47
      without needing to actually sync to the device they are using.

  4.  <b>A server provides automatic off-site backups.</b><p>
      A Fossil server is an automatic remote backup for all the work
      going into a project.  You can even set up multiple servers, at
      multiple sites, with automatic synchronization between them, for
      added redundancy.  Such a set up means that no work is lost due
      to a single machine failure.
Changes to www/serverext.wiki.
199
200
201
202
203
204
205
206
207


208
209
210
211
212
213
214
web browser.  The FOSSIL_NONCE variable contains the value of that nonce.
So, in other words, to get javascript to work, it must be enclosed in:

<blockquote><verbatim>
<script nonce='$FOSSIL_NONCE'>...</script>
</verbatim></blockquote>

Except, of course, the $FOSSIL_NONCE is replace by the value of the
FOSSIL_NONCE environment variable.



If the HTTP request includes content (for example if this is a POST request)
then the CONTENT_LENGTH value will be positive and the data for the content
will be readable on standard input.

<h2>4.0 CGI Outputs</h2>








|

>
>







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
web browser.  The FOSSIL_NONCE variable contains the value of that nonce.
So, in other words, to get javascript to work, it must be enclosed in:

<blockquote><verbatim>
<script nonce='$FOSSIL_NONCE'>...</script>
</verbatim></blockquote>

Except, of course, the $FOSSIL_NONCE is replaced by the value of the
FOSSIL_NONCE environment variable.

<h3>3.1 Input Content</h3>

If the HTTP request includes content (for example if this is a POST request)
then the CONTENT_LENGTH value will be positive and the data for the content
will be readable on standard input.

<h2>4.0 CGI Outputs</h2>

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
image/png.

The fields of the CGI response header can be any valid HTTP header fields.
Those that Fossil does not understand are simply relayed back to up the
line to the requester.

Fossil takes special action with some content types.  If the Content-Type
is "application/x-fossil-wiki" or "application/x-markdown" then Fossil
converts the content from [/wiki_rules|Fossil-Wiki] or 
[/md_rules|Markdown] into HTML, adding its
own header and footer text according to the repository skin.  Content
of type "text/html" is normally passed straight through
unchanged.  However, if the text/html content is of the form:

<blockquote><verbatim>







|







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
image/png.

The fields of the CGI response header can be any valid HTTP header fields.
Those that Fossil does not understand are simply relayed back to up the
line to the requester.

Fossil takes special action with some content types.  If the Content-Type
is "text/x-fossil-wiki" or "text/x-markdown" then Fossil
converts the content from [/wiki_rules|Fossil-Wiki] or 
[/md_rules|Markdown] into HTML, adding its
own header and footer text according to the repository skin.  Content
of type "text/html" is normally passed straight through
unchanged.  However, if the text/html content is of the form:

<blockquote><verbatim>
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
by Fossil.

<h2>6.0 Trouble-Shooting Hints</h2>

Remember that the /ext will return any file in the extroot directory
hierarchy as static content if the file is readable but not executable.
When initially setting up the /ext mechanism, it is sometimes helpful
to verify that you are able to receive static content prior to working
on getting your CGIs working.  Also remember that CGIs must be
executable files.

Fossil likes to run inside a chroot jail, and will automatically put
itself inside a chroot jail if it can.  The sub-CGI program will also
run inside this same chroot jail.  Make sure all embedded pathnames
have been adjusted accordingly and that all resources needed by the
CGI program are available within the chroot jail.







|
|







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
by Fossil.

<h2>6.0 Trouble-Shooting Hints</h2>

Remember that the /ext will return any file in the extroot directory
hierarchy as static content if the file is readable but not executable.
When initially setting up the /ext mechanism, it is sometimes helpful
to verify that you are able to receive static content prior to starting
work on your CGIs.  Also remember that CGIs must be
executable files.

Fossil likes to run inside a chroot jail, and will automatically put
itself inside a chroot jail if it can.  The sub-CGI program will also
run inside this same chroot jail.  Make sure all embedded pathnames
have been adjusted accordingly and that all resources needed by the
CGI program are available within the chroot jail.
Changes to www/ssl.wiki.
102
103
104
105
106
107
108
109





110


111

112
113
114
115
116
117
118
119

120
121



122

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
Beware, taking this path typically opens you up to new problems, which
are conveniently covered in the next section!


<h3 id="certs">Certificates</h3>

To verify the identify of a server, TLS uses
[https://en.wikipedia.org/wiki/X.509#Certificates|X.509 certificates].








If you are using a self-signed certificate, you'll be asked if you want

to accept the certificate the first time you communicate with the
server. Verify the certificate fingerprint is correct, then answer
"always" to remember your decision.

If you are cloning from or syncing to Fossil servers that use a
certificate signed by a
[https://en.wikipedia.org/wiki/Certificate_authority|certificate
authority] (CA), Fossil needs to know which CAs you trust to sign those

certificates. Fossil relies on the OpenSSL library to have some way to
check a trusted list of CA signing keys.





There are two common ways this fails:

  #  <p>The OpenSSL library Fossil is linked to doesn't have a CA
     signing key set at all, so that it initially trusts no certificates
     at all.</p>
  #  <p>The OpenSSL library does have a CA cert set, but your Fossil server's
     TLS certificate was signed by a CA that isn't in that set.</p>

A common reason to fall into the second trap is that you're using
certificates signed by a local private CA, as often happens in large
enterprises.  You can solve this sort of problem by getting your local
CA's signing certificate in PEM format and pointing OpenSSL at it:

<pre>
     fossil set --global ssl-ca-location /path/to/local-ca.pem
</pre>

The use of <tt>--global</tt> with this option is common, since you may
have multiple reposotories served under certificates signed by that same
CA.



A common way to run into the broader first problem is that you're on
FreeBSD, which does not install a CA certificate set by default, even as
a dependency of the OpenSSL library.  If you're using a certificate
signed by one of the major public CAs, you can solve this by installing
the <tt>ca_root_nss</tt> package. That package contains the Mozilla NSS
certificate bundle, which gets installed in a location that OpenSSL
checks by default, so you don't need to change any Fossil settings.
(This is the same certificate set that ships with Firefox, by the way.)

The same sort of thing happens with the Windows build of OpenSSL, but
for a different core reason: Windows does ship with a stock CA
certificate set, but it's not in a format that OpenSSL understands how
to use.  Rather than try to find a way to convert the data format, you
may find it acceptable to use the same Mozilla NSS cert set.  I do not
know of a way to easily get this from Mozilla themselves, but I did find
a [https://curl.haxx.se/docs/caextract.html|third party source] for the
<tt>cacert.pem</tt> file. Install it somewhere on your system, then
point Fossil at it like so:

<pre>
     fossil set --global ssl-ca-location /path/to/cacert.pem
</pre>

This can also happen if you've linked Fossil to a version of OpenSSL
[#openssl-src|built from source]. That same <tt>cacert.pem</tt> fix can
work in that case, too.

When you build Fossil on Linux platforms against the binary OpenSSL







|
>
>
>
>
>

>
>
|
>


|


|
<
|
>
|
<
>
>
>

>
|


















|
>
>

















|
|


|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

126
127
128

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
Beware, taking this path typically opens you up to new problems, which
are conveniently covered in the next section!


<h3 id="certs">Certificates</h3>

To verify the identify of a server, TLS uses
[https://en.wikipedia.org/wiki/X.509#Certificates|X.509 certificates], a
scheme that depends on a trust hierarchy of so-called
[https://en.wikipedia.org/wiki/Certificate_authority | Certificate
Authorities]. The tree of trust relationships ultimately ends in the
CA roots, which are considered the ultimate arbiters of who to trust in
this scheme.

The question then is, what CA roots does Fossil trust?

If you are using a self-signed certificate, Fossil will initially not
know that it can trust your certificate, so you'll be asked if you want
to accept the certificate the first time you communicate with the
server. Verify the certificate fingerprint is correct, then answer
"always" if you want Fossil to remember your decision.

If you are cloning from or syncing to Fossil servers that use a
certificate signed by a well-known CA or one of its delegates, Fossil

still has to know which CA roots to trust. When this fails, you get a
big long error message that starts with this text:


<pre>
    SSL verification failed: unable to get local issuer certificate
</pre>

Fossil relies on the OpenSSL library to have some way to check a trusted
list of CA signing keys. There are two common ways this fails:

  #  <p>The OpenSSL library Fossil is linked to doesn't have a CA
     signing key set at all, so that it initially trusts no certificates
     at all.</p>
  #  <p>The OpenSSL library does have a CA cert set, but your Fossil server's
     TLS certificate was signed by a CA that isn't in that set.</p>

A common reason to fall into the second trap is that you're using
certificates signed by a local private CA, as often happens in large
enterprises.  You can solve this sort of problem by getting your local
CA's signing certificate in PEM format and pointing OpenSSL at it:

<pre>
     fossil set --global ssl-ca-location /path/to/local-ca.pem
</pre>

The use of <tt>--global</tt> with this option is common, since you may
have multiple reposotories served under certificates signed by that same
CA. However, if you have a mix of publicly-signed and locally-signed
certificates, you might want to drop the <tt>--global</tt> flag and set
this option on a per-repository basis instead.

A common way to run into the broader first problem is that you're on
FreeBSD, which does not install a CA certificate set by default, even as
a dependency of the OpenSSL library.  If you're using a certificate
signed by one of the major public CAs, you can solve this by installing
the <tt>ca_root_nss</tt> package. That package contains the Mozilla NSS
certificate bundle, which gets installed in a location that OpenSSL
checks by default, so you don't need to change any Fossil settings.
(This is the same certificate set that ships with Firefox, by the way.)

The same sort of thing happens with the Windows build of OpenSSL, but
for a different core reason: Windows does ship with a stock CA
certificate set, but it's not in a format that OpenSSL understands how
to use.  Rather than try to find a way to convert the data format, you
may find it acceptable to use the same Mozilla NSS cert set.  I do not
know of a way to easily get this from Mozilla themselves, but I did find
a [https://curl.haxx.se/docs/caextract.html|third party source] for the
<tt>cacert.pem</tt> file. I suggest placing the file into your Windows
user home directory so that you can then point Fossil at it like so:

<pre>
     fossil set --global ssl-ca-location %userprofile%\cacert.pem
</pre>

This can also happen if you've linked Fossil to a version of OpenSSL
[#openssl-src|built from source]. That same <tt>cacert.pem</tt> fix can
work in that case, too.

When you build Fossil on Linux platforms against the binary OpenSSL
Changes to www/sync.wiki.
419
420
421
422
423
424
425



426
427
428
429
430
431
432
The receiver of an igot card will typically check to see if
it also holds the same artifact and if not it will request the artifact
using a gimme card in either the reply or in the next message.</p>

<p>If the second argument exists and is "1", then the artifact
identified by the first argument is private on the sender and should
be ignored unless a "--private" [/help?cmd=sync|sync] is occurring.




<h4>3.6.1 Unversioned Igot Cards</h4>

<p>Zero or more "uvigot" cards are sent from server to client when
synchronizing unversioned content.  The format of a uvigot card is
as follows:








>
>
>







419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
The receiver of an igot card will typically check to see if
it also holds the same artifact and if not it will request the artifact
using a gimme card in either the reply or in the next message.</p>

<p>If the second argument exists and is "1", then the artifact
identified by the first argument is private on the sender and should
be ignored unless a "--private" [/help?cmd=sync|sync] is occurring.

<p>The name "igot" comes from the English slang expression "I got" meaning
"I have".

<h4>3.6.1 Unversioned Igot Cards</h4>

<p>Zero or more "uvigot" cards are sent from server to client when
synchronizing unversioned content.  The format of a uvigot card is
as follows:

467
468
469
470
471
472
473




474
475
476
477
478
479
480
</blockquote>

<p>The argument to the gimme card is the ID of the artifact that
the sender wants.  The receiver will typically respond to a
gimme card by sending a file card in its reply or in the next
message.</p>





<h4>3.7.1 Unversioned Gimme Cards</h4>

<p>Sync synchronizing unversioned content, the client may send "uvgimme"
cards to the server.  A uvgimme card requests that the server send
unversioned content to the client.  The format of a uvgimme card is
as follows:








>
>
>
>







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
</blockquote>

<p>The argument to the gimme card is the ID of the artifact that
the sender wants.  The receiver will typically respond to a
gimme card by sending a file card in its reply or in the next
message.</p>

<p>The "gimme" name means "give me".  The imperative "give me" is
pronounced as if it were a single word "gimme" in some dialects of 
English (including the dialect spoken by the original author of Fossil).

<h4>3.7.1 Unversioned Gimme Cards</h4>

<p>Sync synchronizing unversioned content, the client may send "uvgimme"
cards to the server.  A uvgimme card requests that the server send
unversioned content to the client.  The format of a uvgimme card is
as follows:

Changes to www/tech_overview.wiki.
66
67
68
69
70
71
72
73

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

The chart below provides a quick summary of how each of these
database files are used by Fossil, with detailed discussion following.

<table border="1" width="80%" cellpadding="0" align="center">
<tr>
<td width="33%" valign="top">
<h3 align="center">Configuration Database<br>"~/.fossil"</h3>

<ul>
<li>Global [/help/settings |settings]
<li>List of active repositories used by the [/help/all | all] command
</ul>
</td>
<td width="34%" valign="top">
<h3 align="center">Repository Database<br>"<i>project</i>.fossil"</h3>
<ul>
<li>[./fileformat.wiki | Global state of the project]
    encoded using delta-compression
<li>Local [/help/settings|settings]
<li>Web interface display preferences
<li>User credentials and permissions
<li>Metadata about the global state to facilitate rapid
    queries
</ul>
</td>
<td width="33%" valign="top">
<h3 align="center">Checkout Database<br>"_FOSSIL_"</h3>
<ul>
<li>The repository database used by this checkout
<li>The version currently checked out
<li>Other versions [/help/merge | merged] in but not
    yet [/help/commit | committed]
<li>Changes from the [/help/add | add], [/help/delete | delete],
    and [/help/rename | rename] commands that have not yet been committed







|
>


















|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

The chart below provides a quick summary of how each of these
database files are used by Fossil, with detailed discussion following.

<table border="1" width="80%" cellpadding="0" align="center">
<tr>
<td width="33%" valign="top">
<h3 align="center">Configuration Database<br>"~/.fossil" or<br>
"~/.config/fossil.db"</h3>
<ul>
<li>Global [/help/settings |settings]
<li>List of active repositories used by the [/help/all | all] command
</ul>
</td>
<td width="34%" valign="top">
<h3 align="center">Repository Database<br>"<i>project</i>.fossil"</h3>
<ul>
<li>[./fileformat.wiki | Global state of the project]
    encoded using delta-compression
<li>Local [/help/settings|settings]
<li>Web interface display preferences
<li>User credentials and permissions
<li>Metadata about the global state to facilitate rapid
    queries
</ul>
</td>
<td width="33%" valign="top">
<h3 align="center">Checkout Database<br>"_FOSSIL_" or ".fslckout"</h3>
<ul>
<li>The repository database used by this checkout
<li>The version currently checked out
<li>Other versions [/help/merge | merged] in but not
    yet [/help/commit | committed]
<li>Changes from the [/help/add | add], [/help/delete | delete],
    and [/help/rename | rename] commands that have not yet been committed
122
123
124
125
126
127
128



129

130










131

132




133






134


135





136








137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

158
159
160
161

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
a way to change settings for all repositories with a single command, rather
than having to change the setting individually on each repository.

The configuration database also maintains a list of repositories.  This
list is used by the [/help/all | fossil all] command in order to run various
operations such as "sync" or "rebuild" on all repositories managed by a user.




On Unix systems, the configuration database is named ".fossil" and is

located in the user's home directory.  On Windows, the configuration










database is named "_fossil" (using an underscore as the first character

instead of a dot) and is located in the directory specified by the




LOCALAPPDATA, APPDATA, or HOMEPATH environment variables, in that order.









You can override this default location by defining the environment





variable FOSSIL_HOME pointing to an appropriate (writable) directory.









<h3>2.2 Repository Databases</h3>

The repository database is the file that is commonly referred to as
"the repository".  This is because the repository database contains,
among other things, the complete revision, ticket, and wiki history for
a project.  It is customary to name the repository database after then
name of the project, with a ".fossil" suffix.  For example, the repository
database for the self-hosting Fossil repository is called "fossil.fossil"
and the repository database for SQLite is called "sqlite.fossil".

<h4>2.2.1 Global Project State</h4>

The bulk of the repository database (typically 75 to 85%) consists
of the artifacts that comprise the
[./fileformat.wiki | enduring, global, shared state] of the project.
The artifacts are stored as BLOBs, compressed using
[http://www.zlib.net/ | zlib compression] and, where applicable,
using [./delta_encoder_algorithm.wiki | delta compression].
The combination of zlib and delta compression results in a considerable
space savings.  For the SQLite project, at the time of this writing,

the total size of all artifacts is over 2.0 GB but thanks to the
combined zlib and delta compression, that content only takes up
32 MB of space in the repository database, for a compression ratio
of about 64:1.  The average size of a content BLOB in the database

is around 500 bytes.

Note that the zlib and delta compression is not an inherent part of the
Fossil file format; it is just an optimization.
The enduring file format for Fossil is the unordered
set of artifacts. The compression techniques are just a detail of
how the current implementation of Fossil happens to store these artifacts
efficiently on disk.

All of the original uncompressed and un-delta'd artifacts can be extracted
from a Fossil repository database using
the [/help/deconstruct | fossil deconstruct]
command. Individual artifacts can be extracted using the
[/help/artifact | fossil artifact] command.
When accessing the repository database using raw SQL and the
[/help/sqlite3 | fossil sql] command, the extension function
"<tt>content()</tt>" with a single argument which is the SHA1 or
SHA3-256 hash
of an artifact will return the complete undeleted and uncompressed
content of that artifact.

Going the other way, the [/help/reconstruct | fossil reconstruct]
command will scan a directory hierarchy and add all files found to
a new repository database.  The [/help/import | fossil import] command
works by reading the input git-fast-export stream and using it to construct
corresponding artifacts which are then written into the repository database.







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

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




















|
>
|
|
|
|
>
|

















|







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
a way to change settings for all repositories with a single command, rather
than having to change the setting individually on each repository.

The configuration database also maintains a list of repositories.  This
list is used by the [/help/all | fossil all] command in order to run various
operations such as "sync" or "rebuild" on all repositories managed by a user.

<a name='configloc'></a>
<h4>2.1.1 Location Of The Configuration Database</h4>

On Unix systems, the configuration database is named by the following
algorithm:

<blockquote><table border="0">
<tr><td>1. if environment variable FOSSIL_HOME exists
<td>&nbsp;&rarr;&nbsp;<td>$FOSSIL_HOME/.fossil
<tr><td>2. if file ~/.fossil exists<td>&nbsp;&rarr;<td>~/.fossil
<tr><td>3. if environment variable XDG_CONFIG_HOME exists
    <td>&nbsp;&rarr;<td>$XDG_CONFIG_HOME/fossil.db
<tr><td>4. if the directory ~/.config exists
    <td>&nbsp;&rarr;<td>~/.config/fossil.db
<tr><td>5. Otherwise<td>&nbsp;&rarr;<td>~/.fossil
</table></blockquote>

Another way of thinking of this algorithm is the following:

  *  Use "$FOSSIL_HOME/.fossil" if the FOSSIL_HOME variable is defined
  *  Use the XDG-compatible name (usually ~/.config/fossil.db) on XDG systems
     if the ~/.fossil file does not already exist
  *  Otherwise, use the traditional unix name of "~/.fossil"

This algorithm is complex due to the need for historical compatibility.
Originally, the database was always just "~/.fossil".  Then support
for the FOSSIL_HOME environment variable as added.  Later, support for the
[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html|XDG-compatible configation filenames]
was added.  Each of these changes needed to continue to support legacy
installations.

On Windows, the configuration database is the first of the following
for which the corresponding environment variables exist:

  *  %FOSSIL_HOME%/_fossil
  *  %LOCALAPPDATA%/_fossil
  *  %APPDATA%/_fossil
  *  %USERPROFILES%/_fossil
  *  %HOMEDRIVE%%HOMEPATH%/_fossil

The second case is the one that usually determines the name  Note that the
FOSSIL_HOME environment variable can always be set to determine the 
location of the configuration database.  Note also that the configuration
database file itself is called ".fossil" or "fossil.db" on unix but
"_fossil" on windows.

The [/help?cmd=info|fossil info] command will show the location of
the configuration database on a line that starts with "config-db:".

<h3>2.2 Repository Databases</h3>

The repository database is the file that is commonly referred to as
"the repository".  This is because the repository database contains,
among other things, the complete revision, ticket, and wiki history for
a project.  It is customary to name the repository database after then
name of the project, with a ".fossil" suffix.  For example, the repository
database for the self-hosting Fossil repository is called "fossil.fossil"
and the repository database for SQLite is called "sqlite.fossil".

<h4>2.2.1 Global Project State</h4>

The bulk of the repository database (typically 75 to 85%) consists
of the artifacts that comprise the
[./fileformat.wiki | enduring, global, shared state] of the project.
The artifacts are stored as BLOBs, compressed using
[http://www.zlib.net/ | zlib compression] and, where applicable,
using [./delta_encoder_algorithm.wiki | delta compression].
The combination of zlib and delta compression results in a considerable
space savings.  For the SQLite project (when this paragraph was last
updated on 2020-02-08)
the total size of all artifacts is over 7.1 GB but thanks to the
combined zlib and delta compression, that content only takes less than
97 MB of space in the repository database, for a compression ratio
of about 74:1.  The median size of all content BLOBs after delta
and zlib compression have been applied is 156 bytes.
The median size of BLOBs without compression is 45,312 bytes.

Note that the zlib and delta compression is not an inherent part of the
Fossil file format; it is just an optimization.
The enduring file format for Fossil is the unordered
set of artifacts. The compression techniques are just a detail of
how the current implementation of Fossil happens to store these artifacts
efficiently on disk.

All of the original uncompressed and un-delta'd artifacts can be extracted
from a Fossil repository database using
the [/help/deconstruct | fossil deconstruct]
command. Individual artifacts can be extracted using the
[/help/artifact | fossil artifact] command.
When accessing the repository database using raw SQL and the
[/help/sqlite3 | fossil sql] command, the extension function
"<tt>content()</tt>" with a single argument which is the SHA1 or
SHA3-256 hash
of an artifact will return the complete uncompressed
content of that artifact.

Going the other way, the [/help/reconstruct | fossil reconstruct]
command will scan a directory hierarchy and add all files found to
a new repository database.  The [/help/import | fossil import] command
works by reading the input git-fast-export stream and using it to construct
corresponding artifacts which are then written into the repository database.
Changes to www/th1.md.
10
11
12
13
14
15
16
17
18

19
20
21
22
23
24
25
TH1 began as a minimalist re-implementation of the Tcl scripting language.
There was a need to test the SQLite library on Symbian phones, but at that
time all of the test cases for SQLite were written in Tcl and Tcl could not
be easily compiled on the SymbianOS.  So TH1 was developed as a cut-down
version of Tcl that would facilitate running the SQLite test scripts on
SymbianOS.

The testing of SQLite on SymbianOS was eventually accomplished by other
means.  But Fossil was first being designed at about the same time.

Early prototypes of Fossil were written in pure Tcl.  But as the development
shifted toward the use of C-code, the need arose to have a Tcl-like
scripting language to help with code generation.  TH1 was small and
light-weight and used minimal resources and seemed ideally suited for the
task.

The name "TH1" stands "Test Harness 1", since that was its original purpose.







<
|
>







10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
TH1 began as a minimalist re-implementation of the Tcl scripting language.
There was a need to test the SQLite library on Symbian phones, but at that
time all of the test cases for SQLite were written in Tcl and Tcl could not
be easily compiled on the SymbianOS.  So TH1 was developed as a cut-down
version of Tcl that would facilitate running the SQLite test scripts on
SymbianOS.


Fossil was first being designed at about the same time that TH1 was
being developed for testing SQLite on SymbianOS.
Early prototypes of Fossil were written in pure Tcl.  But as the development
shifted toward the use of C-code, the need arose to have a Tcl-like
scripting language to help with code generation.  TH1 was small and
light-weight and used minimal resources and seemed ideally suited for the
task.

The name "TH1" stands "Test Harness 1", since that was its original purpose.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
The text of the command (excluding the newline or semicolon terminator)
is broken into space-separated tokens.  The first token is the command
name and subsequent tokens are the arguments.  In this sense, TH1 syntax
is similar to the familiar command-line shell syntax.

A token is any sequence of characters other than whitespace and semicolons.
Or, all text without double-quotes is a single token even if it includes
whitespace and semicolons.  Or, all text without nested {...} pairs is a
single token.

The nested {...} form of tokens is important because it allows TH1 commands
to have an appearance similar to C/C++.  It is important to remember, though,
that a TH1 script is really just a list of text commands, not a context-free
language with a grammar like C/C++.  This can be confusing to long-time
C/C++ programmers because TH1 does look a lot like C/C++, but the semantics







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
The text of the command (excluding the newline or semicolon terminator)
is broken into space-separated tokens.  The first token is the command
name and subsequent tokens are the arguments.  In this sense, TH1 syntax
is similar to the familiar command-line shell syntax.

A token is any sequence of characters other than whitespace and semicolons.
Or, all text without double-quotes is a single token even if it includes
whitespace and semicolons.  Or, all text within nested {...} pairs is a
single token.

The nested {...} form of tokens is important because it allows TH1 commands
to have an appearance similar to C/C++.  It is important to remember, though,
that a TH1 script is really just a list of text commands, not a context-free
language with a grammar like C/C++.  This can be confusing to long-time
C/C++ programmers because TH1 does look a lot like C/C++, but the semantics
213
214
215
216
217
218
219

220
221
222
223
224
225
226
  *  tclMakeSafe
  *  tclReady
  *  trace
  *  unversioned content
  *  unversioned list
  *  utime
  *  verifyCsrf

  *  wiki

Each of the commands above is documented by a block comment above their
implementation in the th\_main.c or th\_tcl.c source files.

All commands starting with "tcl", with the exception of "tclReady",
require the Tcl integration subsystem be included at compile-time.







>







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  *  tclMakeSafe
  *  tclReady
  *  trace
  *  unversioned content
  *  unversioned list
  *  utime
  *  verifyCsrf
  *  verifyLogin
  *  wiki

Each of the commands above is documented by a block comment above their
implementation in the th\_main.c or th\_tcl.c source files.

All commands starting with "tcl", with the exception of "tclReady",
require the Tcl integration subsystem be included at compile-time.
731
732
733
734
735
736
737








738
739
740
741
742
743
744
  *  verifyCsrf

Before using the results of a form, first call this command to verify
that this Anti-CSRF token is present and is valid.  If the Anti-CSRF token
is missing or is incorrect, that indicates a cross-site scripting attack.
If the event of an attack is detected, an error message is generated and
all further processing is aborted.









<a name="wiki"></a>TH1 wiki Command
-----------------------------------

  *  wiki STRING

Renders STRING as wiki content.







>
>
>
>
>
>
>
>







732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
  *  verifyCsrf

Before using the results of a form, first call this command to verify
that this Anti-CSRF token is present and is valid.  If the Anti-CSRF token
is missing or is incorrect, that indicates a cross-site scripting attack.
If the event of an attack is detected, an error message is generated and
all further processing is aborted.

<a name="verifyLogin"></a>TH1 verifyLogin Command
-------------------------------------------------

  *  verifyLogin

Returns non-zero if the specified user name and password represent a
valid login for the repository.

<a name="wiki"></a>TH1 wiki Command
-----------------------------------

  *  wiki STRING

Renders STRING as wiki content.
Added www/userlinks.wiki.










































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<title>Links For Fossil Users:</title>

  *  [./permutedindex.html | Documentation index] with [/search?c=d | full text search].
  *  [./reviews.wiki | Testimonials] from satisfied Fossil users and
     [./quotes.wiki | Quotes] about Fossil and other DVCSes.
  *  [./faq.wiki | Frequently Asked Questions]
  *  The [./concepts.wiki | concepts] behind Fossil.
     [./whyusefossil.wiki#definitions | Another viewpoint].
  *  [./quickstart.wiki | Quick Start] guide to using Fossil.
  *  [./qandc.wiki | Questions &amp; Criticisms] directed at Fossil.
  *  [./build.wiki | Compiling and Installing]
  *  Fossil supports [./embeddeddoc.wiki | embedded documentation]
     that is versioned along with project source code.
  *  Fossil uses an [./fileformat.wiki | enduring file format] that is
     designed to be readable, searchable, and extensible by people
     not yet born.
  *  A tutorial on [./branching.wiki | branching], what it means and how
     to do it using Fossil.
  *  The [./selfcheck.wiki | automatic self-check] mechanism
     helps insure project integrity.
  *  Fossil contains a [./wikitheory.wiki | built-in wiki].
  *  An [./event.wiki | Event] is a special kind of wiki page associated
     with a point in time rather than a name.
  *  [./settings.wiki | Settings] control the behaviour of Fossil.
  *  [./ssl.wiki | Use SSL] to encrypt communication with the server.
  *  The [https://fossil-scm.org/forum|Fossil forum] is, as of mid-2018,
     the project's central communication channel. The
     [https://www.mail-archive.com/fossil-users@lists.fossil-scm.org
     | read-only mailing list archives] house discussions spanning Fossil's
     first decade.
  *  [./stats.wiki | Performance statistics] taken from real-world projects
     hosted on Fossil.
  *  How to [./shunning.wiki | delete content] from a Fossil repository.
  *  How Fossil does [./password.wiki | password management].
  *  On-line [/help | help].
  *  Documentation on the
     [http://www.sqliteconcepts.org/THManual.pdf | TH1 scripting language],
     used to customize [./custom_ticket.wiki | ticketing], and several other
     subsystems, including [./customskin.md | theming].
  *  List of [./th1.md | TH1 commands provided by Fossil itself] that expose
     its key functionality to TH1 scripts.
  *  List of [./th1-hooks.md | TH1 hooks exposed by Fossil] that enable
     customization of commands and web pages.
  *  A free hosting server for Fossil repositories is available at
     [http://chiselapp.com/].
  *  How to [./server/ | set up a server] for your repository.
  *  Customizing the [./custom_ticket.wiki | ticket system].
  *  Methods to [./checkin_names.wiki | identify a specific check-in].
  *  [./inout.wiki | Import and export] from and to Git.
  *  [./fossil-v-git.wiki | Fossil versus Git].
  *  [./fiveminutes.wiki | Up and running in 5 minutes as a single user]
     (contributed by Gilles Ganault on 2013-01-08).
  *  [./antibot.wiki | How Fossil defends against abuse by spiders and bots].
Changes to www/whyusefossil.wiki.
197
198
199
200
201
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225


226
227
228
229
230
231
232
      </ul>
  <li><p>Two users (or the same user working in different check-outs)
      might commit different changes against the same check-in.  This
      results in one parent node having two or more children.
  <li><p>Command: <b>merge</b> &rarr;
      combines the work of multiple check-ins into
      a single check-out.  That check-out can then be committed to create
      a new that has two (or more) parents.
      <ul>
      <li><p>Most check-ins have just one parent, and either zero or
          one child.
      <li><p>When a check-in has two or more parents, one of those parents
          is the "primary parent". All the other parent nodes are "secondary".

          Conceptually, the primary parent shows the main line of
          development.  Content from the secondary parents is added
          into the main line.
      <li><p>The "direct children" of a check-in X are all children that
          have X as their primary parent.
      <li><p>A check-in node with no direct children is sometimes called
          a "leaf".
      <li><p>The "merge" command changes only the check-out.
          The "commit" command must be run subsequently to make the merge
          a permanent part of project.
      </ul>
  <li><p>Definition: <b>branch</b> &rarr;
      a sequence of check-ins that are all linked
      together in the DAG through the primary parent.
       <ul>
       <li><p>Branches are often given names which propagate to direct children.


       <li><p>It is possible to have multiple branches with the same name.
          Fossil has no problem with this, but it can be confusing to
          humans, so best practice is to give each branch a unique name.
       <li><p>The name of a branch can be changed by adding special tags
          to the first check-in of a branch.  The name assigned by this
          special tag automatically propagates to all direct children.
       </ul>







|




|
>

|














>
>







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
      </ul>
  <li><p>Two users (or the same user working in different check-outs)
      might commit different changes against the same check-in.  This
      results in one parent node having two or more children.
  <li><p>Command: <b>merge</b> &rarr;
      combines the work of multiple check-ins into
      a single check-out.  That check-out can then be committed to create
      a new check-in that has two (or more) parents.
      <ul>
      <li><p>Most check-ins have just one parent, and either zero or
          one child.
      <li><p>When a check-in has two or more parents, one of those parents
          is the "primary parent". All the other parent nodes are "secondary"
          or "merge" parents.
          Conceptually, the primary parent shows the main line of
          development.  Content from the merge parents is added
          into the main line.
      <li><p>The "direct children" of a check-in X are all children that
          have X as their primary parent.
      <li><p>A check-in node with no direct children is sometimes called
          a "leaf".
      <li><p>The "merge" command changes only the check-out.
          The "commit" command must be run subsequently to make the merge
          a permanent part of project.
      </ul>
  <li><p>Definition: <b>branch</b> &rarr;
      a sequence of check-ins that are all linked
      together in the DAG through the primary parent.
       <ul>
       <li><p>Branches are often given names which propagate to direct children.
           The tradition in Fossil is to call the main branch "trunk".  In
           Git, the main branch is usually called "master".
       <li><p>It is possible to have multiple branches with the same name.
          Fossil has no problem with this, but it can be confusing to
          humans, so best practice is to give each branch a unique name.
       <li><p>The name of a branch can be changed by adding special tags
          to the first check-in of a branch.  The name assigned by this
          special tag automatically propagates to all direct children.
       </ul>
Changes to www/wikitheory.wiki.
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<h2>Bug-reports and check-in comments and Forum messages</h2>

The comments on check-ins and the text in the descriptions of bug reports
both use wiki formatting.  Exactly the same set of formatting rules apply.
There is never a need to learn one formatting language for documentation
and a different markup for bugs or for check-in comments.


<h2>Auxiliary notes attached to check-ins or branches</h2>

Stand-alone wiki pages with special names "branch/<i>BRANCHNAME</i>"
or "checkin/<i>HASH</i>" are associated with the corresponding
branch or check-in.  The wiki text appears in an "About" section of
timelines and info screens.  Examples:

   *  [/timeline?r=graph-test-branch] shows the text of the
      [/wiki?name=branch/graph-test-branch|branch/graph-test-branch]
      wiki page at the top of the timeline
   *  [/info/19c60b7fc9e2] shows the text of the
      [/wiki?name=checkin/19c60b7fc9e2400e56a6f938bbad0e34ca746ca2eabdecac10945539f1f5e8c6|checkin/19c60b7fc9e2...]
      wiki page in the "About" section.

This special wiki pages are very useful for recording historical
notes.







>








|


|




63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<h2>Bug-reports and check-in comments and Forum messages</h2>

The comments on check-ins and the text in the descriptions of bug reports
both use wiki formatting.  Exactly the same set of formatting rules apply.
There is never a need to learn one formatting language for documentation
and a different markup for bugs or for check-in comments.

<a name="assocwiki"></a>
<h2>Auxiliary notes attached to check-ins or branches</h2>

Stand-alone wiki pages with special names "branch/<i>BRANCHNAME</i>"
or "checkin/<i>HASH</i>" are associated with the corresponding
branch or check-in.  The wiki text appears in an "About" section of
timelines and info screens.  Examples:

   *  [/timeline?r=graph-test-branch] shows the text of the
      [/wiki?name=branch/graph-test-branch&p|branch/graph-test-branch]
      wiki page at the top of the timeline
   *  [/info/19c60b7fc9e2] shows the text of the
      [/wiki?name=checkin/19c60b7fc9e2400e56a6f938bbad0e34ca746ca2eabdecac10945539f1f5e8c6&p|checkin/19c60b7fc9e2...]
      wiki page in the "About" section.

This special wiki pages are very useful for recording historical
notes.